我对JS中如何调度异步任务的理解
如果我说错了什么,请纠正我:
JS运行时引擎代理由一个事件循环驱动,该循环收集任何用户和其他事件,将任务排入队列以处理每个回调。
事件循环持续运行,并具有以下思维过程:
所以这里有两个关键的区别b/w如何处理任务和微任务:
Promises是在ES6 2015..。我假设微任务队列也是在ES6中引入的。
我的问题
引入微任务队列的动机是什么?为什么不继续使用promises的任务队列呢?
更新#1 -我正在寻找规范更改的明确历史原因-即它旨在解决的问题是什么,而不是关于微任务队列的好处的固执己见的答案。
参考文献:
发布于 2021-02-26 21:01:28
Promises是在ES6 2015中引入的。我假设微任务队列也是在ES6中引入的。
实际上,微任务任务队列根本不是由ECMAScript标准引入的: ES6标准指定将已解决的promise的promise处理作业放在名为"PromiseJobs“的队列中TriggerPromiseReactions,使用抽象过程EnqueueJob
在不规定如何处理主机队列的情况下,将作业输入由主机环境实现的作业队列中。
在被ECMAScript采用之前
Promise库是在用户领域开发的。执行promise处理程序、监视它们是否抛出或返回值并有权访问resolve 和 reject
promise链中下一个promise的功能被称为"trampoline“。虽然是Promise库的一部分,但trampoline不被认为是用户代码的一部分,并且声称使用干净的堆栈调用promise处理程序排除了由trampoline占用的堆栈空间。
使用处理程序列表来调用已解决状态(已履行或已拒绝)的promise的结算需要启动trampoline来运行promise作业(如果它尚未运行)。
使用空栈启动trampoline执行的方法仅限于现有的浏览器API,包括
setTimeout, setImmediate和变异观察者API..。变异观察者使用微任务队列并且可能是引入它的原因(不确定确切的浏览器历史)。
事件循环接口的可能性,setImmediate至少Mozilla从未实现过,根据MDN的说法,突变观察者在IE11中是可用的。setTimeout在某些情况下会受到限制,因此即使延迟时间设置为零,执行回调也至少需要几毫秒。
开发者竞赛
对于外部观察者来说,promise库开发人员相互竞争,看谁能在promise结算后提出最快的时间来开始执行promise处理程序。
这就引出了setImmediate polyfills根据浏览器中的可用内容,选择了从事件循环启动对trampoline的回调的最快策略。
YuzuJS / setImmediate on GitHub是这种多边形填充的一个主要示例,它的readme很值得一读。
在ECMAScript 2015中采用后的历史
promise包含在ES6中,但没有指定主机实现应给予promise作业的优先级。
这本书的作者
上面的polyfill还向TC39委员会提交了一份文件,指定promise作业应该在ECMAScript中具有高优先级。该提交最终被拒绝,因为这是一个不属于该语言标准的实现问题。支持提交的参数在TC39's tracking siteTC39的追踪网站因为它没有引用被拒绝的提案。
随后,HTML5规范引入了浏览器中Promise实现的规则。The The The
一节介绍如何在主机浏览器中实现ECMAScipt的EnqueueJob抽象操作指定它们进入微任务队列。
答案
引入微任务队列的动机是什么?为什么不继续使用promises的任务队列呢?
微任务队列可能是为了支持突变观察者事件而引入的。
promise库的早期开发人员找到了在微任务队列中输入作业的方法,并通过这样做最小化了结算promise和运行promise反应作业之间的时间。在某种程度上,这造成了开发人员之间的竞争,但也促进了在处理异步操作序列中的一个步骤的完成后尽快继续异步程序操作。
通过设计,可以将实现和拒绝处理程序添加到已经确定的承诺中。如果出现这种情况,那么在进入promise链的下一步之前,不需要等待什么事情发生。在这里使用微任务队列意味着下一个promise处理程序是异步执行的,具有干净的堆栈,或多或少是立即执行的。
最终,指定微任务队列的决定是由著名的开发人员和公司基于他们的专家意见做出的。虽然这可能是一个很好的选择,但这样做的绝对必要性是没有意义的。
另请参阅
通过queueMicrotask()在JavaScript中使用微任务
在MDN上。
发布于 2021-02-14 06:49:13
一个优点是,不同实现之间的可观察行为的可能差异较小。
如果没有对这些队列进行分类,那么在确定如何对一个队列进行排序时,将会有未定义的行为setTimeout(..., 0)回调与a promise.then(...)严格按照规范回调。
我认为,选择将这些队列分为微任务和“宏”任务可以减少由于异步中的竞争条件而可能出现的bug类型。
这一好处对JavaScript库开发人员特别有吸引力,他们的目标通常是生成高度优化的代码,同时在引擎之间保持一致的可观察行为。
发布于 2021-02-24 07:52:51
我发现了这个(https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)相对较旧的博客文章很好地解释了这一点,它还给出了一些关于旧浏览器版本的示例。
分离与HTML相关的任务和“工作”/微任务相关的工作。
我认为这一行为对于支持浏览器上的工作人员是必要的。工作人员不能访问DOM,因此他们也必须想出一种新的机制来解决这个问题。
https://stackoverflow.com/questions/66190571
复制相似问题