我正在基于游戲回圈在 nodejs 中撰寫應用程式。回圈的每次迭代都會觸發一個事件發射器,并呼叫一個更新方法,如下所示:
updateLoop() {
while (!this.windowShouldClose()) {
this.onUpdate.emit();
this.update();
}
}
似乎事件發射器可以幫助在不同操作之間等待幀的游戲物件上撰寫異步函式,就像一個協程。我撰寫了一個實用程式函式,它會在事件發射器的下一次發射時回呼或決議承諾:
nextFrame() {
return new Promise((resolve) => {
this.onUpdate.once(resolve); // event emitter will resolve promise on next emit()
})
}
nextFrameCallback(callback) {
this.onUpdate.once(callback);
}
// example use
async doThingsAsync() {
// do something
await this.nextFrame();
// do something else on the next frame / loop iteration
}
雖然基于回呼的函式按預期作業,但 nextFrame() 的承諾版本并沒有在我期望的時候解決承諾。await nextFrame()僅在我的示例中的外回圈updateLoop()退出后才會決議。我將 console.log 附加到承諾以了解更多資訊,并發現控制臺日志和 resolve() 確實在回圈內被呼叫,但等待它仍然會等待回圈完全終止。
nextFrameDebug() {
return new Promise((resolve) => {
this.onUpdate.once(() => {
console.log('debug nextFrame'); // this prints during the expected loop iteration
resolve(); // this does not actually resolve until updateLoop() terminates
})
})
}
這是一個演示上述功能的 JSFiddle:https ://jsfiddle.net/8L4wub29/5/
似乎我已經接近功能解決方案了,但是我對 promise 或異步函式有一些誤解。這是否與從回圈內呼叫異步函式有關?我如何撰寫 nextFrame() 以便承諾在回圈的下一次迭代中解決,而不是在回圈退出之后?我意識到對于游戲中的大多數功能,以毫秒為單位的超時更有用,但在某些情況下,例如等待物理更新,游戲可能只想等待一幀作為效用函式。基于回呼的版本作業正常,但如果你需要多次使用它那么你需要嵌套它,這看起來不像使用那么干凈await
uj5u.com熱心網友回復:
Promise 保證它們的.then回呼將始終被異步呼叫。這意味著如果你有一些隨機的承諾,你會做這樣的事情:
somePromise.then(() => {
console.log('inside');
});
console.log('outside');
即使承諾恰好已經處于已解決狀態,您也會始終看到“外部”和“內部”。Promise 是這樣設計的,因此您可以確定執行順序,因此不必修復涉及兩個順序的痛苦錯誤。當您使用await而不是顯式.then's 時也是如此:await必須等到承諾決議之后的代碼,并且呼叫堆疊回傳到系統代碼。
因此,當您從回呼切換到承諾時,您從可以在回圈中間同步呼叫回呼的代碼轉到必須等待執行回傳的代碼。Promise 之后updateLoop的代碼只有一次回傳或產生才能運行。由于該回圈在結束之前永遠不會回傳或產生,因此所有承諾都會延遲到回圈之后。
如果您需要updateLoop同步運行,那么您不能為此使用承諾。如果相反updateLoop應該是異步的(可能在運行下一步之前設定超時),那么可以使用承諾,但我需要更多關于您正在嘗試做什么的詳細資訊來舉例說明。
uj5u.com熱心網友回復:
回答我自己的問題,因為我發現了一些提供預期功能的東西。我只是將示例中的 updateLoop() 呼叫更新為此。
async updateLoop() {
while (!this.windowShouldClose()) {
await null;
this.onUpdate.emit();
this.update();
}
}
有人能更清楚地評論為什么現在會產生預期的效果嗎?除非我添加 await 陳述句,否則將函式更改為 async 不會影響承諾決議的時間點。我的假設是包含一個 await 陳述句釋放了最終允許承諾解決的事件回圈。如果您使用此函式編輯上面的 JSfiddle,則控制臺中列印的數字將與列印陳述句“期望”的數字不一致 - 僅與計數器增加有關。執行順序似乎是正確的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/389477.html
標籤:javascript 节点.js 异步 异步等待 承诺
下一篇:React-如何回到默認狀態?
