Cle*_*ent 2 javascript w3c asynchronous vm-implementation
根据我对javascript虚拟机如何工作的全球理解,我可以清楚地看到微任务/宏任务的概念起着重要作用.
以下是我对此的理解:
以下是我的问题:
为什么没有明确的API来操纵这两个队列.
就像是
pushToMacroTask( function )pushToMicroTask( function )实际上,接触操作这些队列的唯一方法就是使用setTimeout()将任务添加到宏任务队列Promises并将任务添加到微任务队列......
我很好,但是这并没有给我们一个有意义的API,你不觉得吗?
这个概念是否应该保留给JS开发者"隐藏"并仅用于某些hacky情况?
你知道围绕这个主题是否有任何W3C规范?
所有VM引擎都以同样的方式实现这个概念吗?
我很乐意听到有关这方面的故事和意见.
谢谢 !
W3C谈到任务队列:
当用户代理要对任务进行排队时,它必须将给定任务添加到相关事件循环的任务队列之一.来自一个特定任务源的所有任务(例如,计时器生成的回调,为鼠标移动调度的事件,排队等待解析器的任务)必须始终添加到同一任务队列,但可以将来自不同任务源的任务放入不同的任务队列.
EcmaScript2015讲述了作业队列,并要求至少支持两种:
- ScriptJobs:验证和评估ECMAScript脚本和模块源文本的作业.
- PromiseJobs:回应Promise的工作.
此语言定义不了解可能的事件循环,但可以想象一个或多个作业队列被保留用于W3C规范中提到的任务队列.浏览器将setTimeout根据W3C任务队列规范(链接到作业队列)触发回调,而承诺必须直接使用作业队列规范(而不是任务队列).还提到了代理可以将任务注入作业队列:
或者,[实现]可能会选择等待某个特定于实现的代理或机制来排队新的PendingJob请求.
EcmaScript规范不强制优先处理不同的作业队列:
此规范未定义服务多个作业队列的顺序.ECMAScript实现可以将作业队列的PendingJob记录的FIFO评估与一个或多个其他作业队列的PendingJob记录的评估交织在一起.
所以,这里似乎没有严格的要求,承诺履行应该在setTimeout任务之前得到服务.但是,当覆盖事件循环时,Web超文本应用技术工作组更具体 :
每个事件循环都有一个微任务队列.微任务是最初要在微任务队列而不是任务队列上排队的任务.
该文章可能是一个有趣的阅读,显示浏览器的实现方式有什么不同导致不同的执行顺序:
一些浏览器之后正在运行promise回调
setTimeout.很可能他们将承诺回调称为新任务的一部分而不是微任务.Firefox和Safari正在耗尽点击侦听器之间的微任务队列,如变异回调所示,但承诺似乎排队不同.[...]有了Edge,我们已经看到它错误地排队了,但它也无法耗尽点击侦听器之间的微任务队列,而是在调用所有侦听器之后这样做.
本文写于2015年8月,从那时起,几个问题得到了解决和协调.
但请注意,不必有一个微任务队列,也不一个宏任务队列.可以有几个队列,每个队列都有自己的优先级.
实现您建议的两个功能当然不是那么困难:
let pushToMicroTask = f => Promise.resolve().then(f);
let pushToMacroTask = f => setTimeout(f);
let say = msg => console.log(msg);
pushToMacroTask(say.bind(null, 'Macro task runs last'));
pushToMicroTask(say.bind(null, 'Micro task runs first'));Run Code Online (Sandbox Code Playgroud)