为什么Promise库使用事件循环?
Why do Promise libraries use event loops?
考虑以下JavaScript代码:
var promise = new Promise();
setTimeout(function() {
promise.resolve();
}, 10);
function foo() { }
promise.then(foo);
在我所见过的承诺实现中,promise.resolve()会简单地设置一些属性来表明承诺被解析,然后在事件循环期间调用foo(),但似乎promise.resolve()会有足够的信息来立即调用任何延迟的函数,如foo()。
事件循环方法似乎会增加复杂性并降低性能,那么为什么要使用它?
虽然我大部分使用的承诺是与JavaScript,我的问题的部分原因是在实现承诺非常性能密集型的情况下,如c++游戏,在这种情况下,我想知道我是否可以利用承诺的一些好处没有事件循环的开销。
所有的承诺实现,至少好的都是这样做的。
这是因为在异步API中混合同步会释放Zalgo。
承诺有时不会立即解决,有时会延迟解决,这意味着API是一致的。否则,将在执行顺序中得到未定义的行为。
function getFromCache(){
return Promise.resolve(cachedValue || getFromWebAndCache());
}
getFromCache().then(function(x){
alert("World");
});
alert("Hello");
承诺库延迟的事实意味着上面块的执行顺序是有保证的。在像jQuery这样的失信实现中,顺序取决于是否从缓存中获取条目。这很危险。
不确定的执行顺序是非常危险的,也是bug的常见来源。Promises/A+规范把你扔进了成功的坑里。
promise.resolve()
是否同步或异步执行其延续实际上取决于实现。
此外,"事件循环"并不是提供不同"执行上下文"的唯一机制。可能还有其他方法,例如线程或线程池,或者考虑GCD (Grand Central Dispatch,调度库),它提供调度队列。
Promises/A+ Spec明确要求延续(onFulfilled
分别是onRejected
处理程序)将在调用then
方法的"执行上下文"中异步执行。
在执行上下文堆栈只包含平台代码之前,不能调用
onFulfilled
或onRejected
。[3.1]。
在注释下面你可以读到它的实际意思:
这里的"平台代码"是指引擎、环境和承诺实现代码。在实践中,这个要求确保onfulfillment和onRejected在调用then的事件循环之后异步执行,并且使用一个新的堆栈。
在这里,每个事件将在不同的"执行上下文"中执行,即使这是相同的事件循环和相同的"线程"。
由于Promises/A+规范是为Javascript环境编写的,一个更通用的规范将只要求延续相对于调用then
方法的调用者异步执行。
这样做有很好的理由!
示例(伪代码):promise = async_task();
printf("a");
promise.then((int result){
printf("b");
});
printf("c");
假设处理程序(延续)将在与调用站点相同的线程上执行,执行顺序应该是控制台显示的:
acb
特别是,当承诺已经被解决时,一些实现倾向于在相同的执行上下文中"立即"调用延续(即同步地)。这显然违反了上述规则。规则总是异步地调用延续的原因是调用站点需要保证处理程序和then
后面的代码的相对执行顺序,包括在任何场景中的延续语句。也就是说,无论promise是否已经被解析,语句的执行顺序必须是相同的。否则,更复杂的异步系统可能无法可靠地工作。
resolve
函数的延续将被同步地调用。当异步任务将在稍后的事件循环周期中完成时,这甚至会出现问题,因此延续将确实相对于调用站点异步执行。
然而,当异步任务完成后调用resolve
函数时,该任务可能在私有执行上下文中执行(例如"工作线程")。这个"工作线程"通常是一个专用的,也可能是特殊配置的执行上下文——然后调用resolve
。如果resolve
函数将同步地执行延续,那么延续将在任务的私有执行上下文中运行——这通常是不希望的。
承诺都是关于合作的多任务处理。
实现这一目标的唯一方法是使用基于消息的调度。计时器(通常具有0延迟)仅用于将任务/消息发布到消息队列中- yield-to-next-task-in- queue范式。因此,由小事件处理程序组成的整个结构可以正常工作,并且您产生的频率越高,所有这些工作就越顺利。
- 具有Qt事件循环的可移植通用共享库设置
- 如何将事件循环中的事件分派给订阅者?
- C++uWebSockets将事件循环集成到一个线程中
- 了解如何在不冻结事件循环的情况下在 QThread 中休眠/等待
- 如何在主事件循环之前创建一些对象?
- Libuv:保护事件循环免受并发访问
- 防止模式对话框中的事件循环阻塞
- QCoreApplication事件循环和Windows服务控制处理程序功能
- c++ 过期映射条目线程与事件循环
- Qt的事件循环线程是安全的还是原子的?处理"队列连接"时如何同步?
- 在事件循环启动后删除并创建新的 RTP 流
- QSTATEMACHINE事件循环与动画
- 等待事件循环为空 /等到QT5小部件关闭
- 如何将lambda函数排队到Qt的事件循环中?
- DLL中的QT事件循环
- 运行Qt 5.10事件循环howto的Windows服务service_WIN32_OWN_PROCESS
- 模态qprogressdialog :: setValue()导致嵌套事件循环崩溃
- 什么是QT中的事件循环
- Libuv中SD-BUS的事件循环处理
- Qt的事件循环是FIFO吗?