最近nodejsサーバーを取得しているので、結果はzeromqによって実装されたrpcになります。rpcがスタックしていることがわかりました。メッセージを出力した後、zeromqメッセージは主に失われました。送信後、受信側はそれを受信しませんでした。すると、サンプルコードではasync / awaitという非同期コードが使われていることがわかりましたが、理解できないので、覚えてメモを取るための資料を見つけました。
問題
- zeromqで非同期モードを使用する理由
- 非同期関数の戻り値を取得するにはどうすればよいですか?
これは最初からのコードです:
function sendMsg(server, msg, uniqueId) {
if (!this.socket) {
return null;
}
var rid;
if (uniqueId === undefined) {
rid = uuid.v4() + '_' + this.id;
} else {
rid = uniqueId;
}
this.socket.send([MDP.REQUEST, server, rid, JSON.stringify(msg)])
return rid;
}
理解する
一般に、Promiseとasync / awaitはどちらも非同期呼び出しであり、「リージョンコールバック」の問題を解決できます。そしてasync / awaitは同期コードの方法に沿ってより多く書かれています、理解するためにそれをもっとよく読んでください、[1]を参照してください
約束する
Promiseはもともとコールバックの問題を解決するために設計されました。[2] [3]を参照してください
Promiseは、非同期操作の最終的な完了または失敗を表すオブジェクトです
簡単に言うと、非同期呼び出しの後に成功と失敗があります。非同期呼び出しが完了した後、それらを均一に処理でき、各ブランチでコールバックを処理する必要はありません。つまり、コールバックを渡す必要はありませんが、Promiseオブジェクトの最終処理です。それをどう扱うか?その時点は、Promise.then関数です。
const promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
promise1.then(function(value) {
console.log(value);
// expected output: "foo"
});
console.log(promise1);
// expected output: [object Promise]
さらに、thenパラメータは関数であり、多くの場合、arrow関数[4]が表示されるため、最初は少し奇妙に感じるでしょう。
非同期
非同期は理解しやすく、非同期関数です。参考資料[5]
戻り値はPomiseオブジェクトであるため、最初のsendMsg関数は次の形式で記述されており、sendMsgを同期的に呼び出して取得した戻り値ridは間違っています。最初にも問題が発生しました
async function sendMsg(server, msg, uniqueId) {
// 省略
await this.socket.send([MDP.REQUEST, server, rid, JSON.stringify(msg)])
return rid;
}
もう1つは、非同期でawaitを使用して、非同期機能を中断できることです。この時点で返されたyieldはPromiseオブジェクトであることを理解しています、あなたがすぐに待っている場合でも、戻り値自体もPromiseオブジェクトです
async function test1(){
var a = await 3;
return a;
}
console.log(test1())
console.log(test1().then((resolve, reject)=>{
console.log('resolve:', resolve)
}))
//结果
Promise { <pending> }
Promise { <pending> }
resolve: 3
待つ
Awaitはおそらく以下の点を持っています。[6]を参照してください:
- 非同期関数でのみ使用できます
- await式は、現在の非同期関数の実行を中断し、Promise処理の完了を待ちます。
- これは非同期呼び出しなので、この時点でawaitによってasyncが中断された場合、実行は続行されますが、ここでブロックおよび停止することはありません。返されたPromiseオブジェクトですが、このPromiseオブジェクトはまだ処理されていないため、返されたPromise.then関数はまだ実行されていません。
[5]の例を見てみましょう
var resolveAfter2Seconds = function() {
console.log("starting slow promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("slow");
console.log("slow promise is done");
}, 2000);
});
};
var resolveAfter1Second = function() {
console.log("starting fast promise");
return new Promise(resolve => {
setTimeout(function() {
resolve("fast");
console.log("fast promise is done");
}, 1000);
});
};
var concurrentStart = async function() {
console.log('==CONCURRENT START with await==');
const slow = resolveAfter2Seconds(); // starts timer immediately
const fast = resolveAfter1Second(); // starts timer immediately
// 1. Execution gets here almost instantly
console.log(await slow); // 2. this runs 2 seconds after 1.
console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved
}
結果:
==CONCURRENT START with await==
starting slow promise
starting fast promise
fast promise is done
slow promise is done
slow
fast
(1)resolveAfter2SecondsとresolveAfter1Secondの2つの関数は待機せずに同じフレームで実行されるため、最初の3枚の印刷はすぐに出力されます
(2)4番目の印刷高速プロミスは最初の1秒の終わりに印刷されます。 resolveAfter1Second関数が実行され、Promiseが処理されます
(3)awaitがasyncの最後のconsole.logの実行をブロックするため、最後の3つの印刷は一緒に印刷されます。速い約束が扱われたとしても
ソリューションと要約
非同期関数を別の関数から引き出します。sendMsgの戻り値には影響しません
async function send(msg) {
if (!this.socket) {
return;
}
try {
await this.socket.send(msg);
}catch(err){
console.error('unable to send')
}
}
function sendMsg(server, msg, uniqueId) {
// 省略
send.call(this, [MDP.REQUEST, server, rid, JSON.stringify(msg)]).then((resolve, reject)=>{
console.log('send result...........', resolve, reject)
});
return rid;
}
参考資料
[1] Nodejsでの非同期処理の進化
[2] Promise
[3] Promiseは
[4] 矢印関数を使用
[5] async
[6] await
[7] Async / Await in Nodejs
[8]
[9] マスター非同期/ Node.jsで待機