言及:Marius Tibeicaの回答は完全で素晴らしいものであり、david_pのコメントもあります。Rob Raischの答えもそうです(探索するのは興味深いです)。
https://stackoverflow.com/a/27040451/7668448
https://stackoverflow.com/a/13326769/7668448
知らせ
この最初の方法は悪い方法です!参考にしておきます!更新セクションを参照してください!良いバージョンのために!また、その理由の説明も!
悪いバージョン
これが便利だと思う人のために、ここではビジーポート処理を実装する関数を使用します(ポートがビジーの場合、ビジーポートがなくなるまで次のポートで試行します)
app.portNumber = 4000;
function listen(port) {
app.portNumber = port;
app.listen(port, () => {
console.log("server is running on port :" + app.portNumber);
}).on('error', function (err) {
if(err.errno === 'EADDRINUSE') {
console.log(`----- Port ${port} is busy, trying with port ${port + 1} -----`);
listen(port + 1)
} else {
console.log(err);
}
});
}
listen(app.portNumber);
関数listenは、それ自体を再帰的に呼び出しています。ポートビジーエラーの場合。毎回ポート番号をインクリメントします。
更新完全にやり直し
コールバックフルバージョン
まず第一に、このバージョンはnodejshttp.Server.listen()
メソッドと同じシグネチャに従うバージョンです!
function listen(server) {
const args = Array.from(arguments);
// __________________________________ overriding the callback method (closure to pass port)
const lastArgIndex = arguments.length - 1;
let port = args[1];
if (typeof args[lastArgIndex] === 'function') {
const callback = args[lastArgIndex];
args[lastArgIndex] = function () {
callback(port);
}
}
const serverInstance = server.listen.apply(server, args.slice(1))
.on('error', function (err) {
if(err.errno === 'EADDRINUSE') {
console.log(`----- Port ${port} is busy, trying with port ${port + 1} -----`);
port += 1;
serverInstance.listen.apply(serverInstance, [port].concat(args.slice(2, lastArgIndex)));
} else {
console.log(err);
}
});
return serverInstance;
}
サイン:
listen(serverOrExpressApp、[port [、host [、backlog]]] [、callback])
と同じように
https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
コールバック署名がに変更されます
(ポート)=>無効
利用方法:
const server = listen(app, 3000, (port) => {
console.log("server is running on port :" + port);
});
// _____________ another example port and host
const server = listen(app, 3000, 'localhost', (port) => {
console.log("server is running on port :" + port);
});
説明
古い例とは対照的に!このメソッドはそれ自体を呼び出しません!
重要な要素:
- app.listen()の最初の呼び出しは、net.Serverインスタンスを返します
- イベントを一度バインドした後、同じnet.Serverインスタンスにもう一度listenを呼び出すと、再接続が試行されます。
- エラーイベントリスナーは常にそこにあります!
- エラーが発生するたびに、再試行します。
- ポート変数は、コールバックへのクロージャで再生されます!コールバックが呼び出されると、正しい値が渡されます。
重要なのは
serverInstance.listen.apply(serverInstance, [port].concat(args.slice(2, lastArgIndex)));
ここでコールバックをスキップするのはなぜですか!?
コールバックが追加されたら!これは、サーバーインスタンスの内部で配列に保持されます。別のものを追加すると!複数のトリガーがあります!(試行+1)の数について。したがって、最初の試行にのみ含めます。
そうすれば、サーバーインスタンスを直接返すことができます。そしてそれを使って試み続けてください!そして、それはきれいに行われます!
シンプルバージョンポートのみ
それも一瞥でよりよく理解するのに役立ちます
function listen(server, port, callback) {
const serverInstance = server.listen(port, () => { callback(port) })
.on('error', function (err) {
if(err.errno === 'EADDRINUSE') {
console.log(`----- Port ${port} is busy, trying with port ${port + 1} -----`);
port += 1;
serverInstance.listen(port);
} else {
console.log(err);
}
});
return serverInstance;
}
ここで、パラメーターポート変数はクロージャーで再生されます!
ES6フルバージョン
function listen(server, ...args) {
// __________________________________ overriding the callback method (closure to pass port)
const lastArgIndex = args.length - 1;
let port = args[0];
if (typeof args[lastArgIndex] === 'function') {
const callback = args[lastArgIndex];
args[lastArgIndex] = function () {
callback(port);
}
}
const serverInstance = server.listen(server, ...args)
.on('error', function (err) {
if(err.errno === 'EADDRINUSE') {
console.log(`----- Port ${port} is busy, trying with port ${port + 1} -----`);
port += 1;
serverInstance.listen(...[port, ...args.slice(1, lastArgIndex)])
} else {
console.log(err);
}
});
return serverInstance;
}
古いバージョンが悪い理由
正しく言うと、そうではありません!しかし、最初のバージョンでは!失敗するたびに関数自体を呼び出します。そして、それが新しいインスタンスを作成するたびに!ガベージコレクターはいくつかの筋肉を動かします!
この関数は開始時に1回だけ実行されるため、問題ありません。
古いバージョンはサーバーインスタンスを返しませんでした!
追加(@ sakib11の場合)
@ sakib11のコメントを見て、彼がどのような問題に陥っているのかを確認できます。思いやりがあります!
また、コメントの中で、promiseバージョンとクロージャーゲッターパターンについて言及しました!私はそれらを面白いとは思わない!上記の方法は、nodejsと同じ署名を尊重するだけです!そして、コールバックもうまくいきます!そして、サーバー参照を書き留めています!約束バージョン付き!約束が返され、解決策ですべての要素を渡します!serverInstance +ポート!
そして、クロージャーゲッターパターンが気になるなら!(ここは悪いです)
このメソッド内で、サーバーインスタンスを参照する参照を作成します。実行中にサーバーインスタンスを返すことができなかった場合(イメージングは不可能でした!したがって、新しいインスタンスが作成されるたびに!パターンはクロージャー(そのスコープのメソッド)を作成して返します!
だから使用のために
const getServer = listen(port, () => {
console.log('Server running at port ' + getServer().address().port);
const io = socketIo(getServer(), {});
});
しかし、それはただのオーバーヘッドであり、特にサーバーが完了するのを待つ必要があります!コールバックを使用するように設定しない限り!または約束を返します!
そして、それは複雑すぎます!そして、まったく良くありません!
それは私がそれを言ったからです!
そして、上記の方法は微調整することができます!試行回数制限を追加するには!そして、いくつかのイベントやフックを追加してください!しかしよく!通常、必要なのは、試行して作成するだけの単純な関数だけです。私にとっては、上記で十分です。
良いリンク
ドキュメントから
app.listen()メソッドはhttp.Serverオブジェクトを返し、(HTTPの場合)次の便利なメソッドです。
app.listen = function () {
var server = http.createServer(this)
return server.listen.apply(server, arguments)
}