我正在用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来承诺查找更多的内容,并发现控制台日志和解析()确实在循环中被调用,但是等待它仍然会等待循环完全终止。
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/ --似乎我已经接近了一个功能解决方案,但是我对承诺或异步函数有一些误解。这与从循环中调用异步函数有关吗?我如何编写nextFrame()以使承诺在循环的下一次迭代中得到解决,而不是在循环退出之后?我意识到,对于游戏中的大多数功能,毫秒的超时更有用,但在某些情况下,比如等待物理更新,游戏可能希望只等待一个帧作为实用函数。基于回调的版本工作正常,但是如果您需要多次使用它,则需要嵌套它,这看起来不像使用await
那么干净。
发布于 2021-12-21 15:17:29
承诺提供的保证是,它们的.then
回调将始终被异步调用。这意味着,如果你有一些随机的承诺,你会做这样的事情:
somePromise.then(() => {
console.log('inside');
});
console.log('outside');
您将始终看到“外部”和“内部”,即使承诺已经处于已解决的状态。承诺是这样设计的,因此您可以确定执行的顺序,因此不必修复涉及这两个订单的痛苦错误。当您使用await
而不是显式.then
的时候,情况也是一样:await
之后的代码必须等待承诺解决,并且调用堆栈返回到系统代码。
因此,当您从回调切换到承诺时,您从可以在循环中间同步调用回调的代码转变为必须等待执行才能返回的代码。只有在updateLoop
返回或生成之后,代码才能在承诺之后运行。因为这个循环直到结束才会返回或屈服,所以所有的承诺都会被推迟到循环之后。
如果您需要updateLoop
同步运行,则不能使用此承诺。如果updateLoop
应该是异步的(可能在运行下一步之前设置超时),那么可以使用承诺,但是我需要更多的细节来说明您试图做什么来给出一个示例。
发布于 2021-12-21 17:27:01
回答我自己的问题,因为我找到了提供预期功能的东西。我只是简单地更新了示例中的updateLoop()调用。
async updateLoop() {
while (!this.windowShouldClose()) {
await null;
this.onUpdate.emit();
this.update();
}
}
有人能在更明确的情况下发表评论吗?为什么现在会产生预期的效果?除非我添加了一个等待语句,否则将函数更改为异步不会影响承诺的解析点。我的假设是,包括一个等待语句,释放事件循环,这最终允许承诺解决。如果使用此函数编辑上述JSfiddle,则控制台中打印的数字将与打印语句"expect“不一致--这仅与计数器增加有关。执行命令似乎是正确的。
https://stackoverflow.com/questions/70442303
复制相似问题