从我对javascript虚拟机工作方式的全球理解中,我可以清楚地看到,微任务/宏任务的概念发挥了很大的作用。
以下是我对此的理解:
我的问题是:
为什么没有明确的API来操作这两个队列.
有点像
pushToMacroTask( function )pushToMicroTask( function )实际上,操纵这些队列的唯一方法是使用setTimeout()将任务添加到宏任务队列中,使用Promises将任务添加到微任务队列中。
我同意,但这并不能给我们一个有意义的API,你不认为吗?
这个概念对JS来说应该是“隐藏”的,并且只在一些讨厌的情况下使用吗?
你知道那个主题是否有W3C规范吗?
是否所有VM引擎都以相同的方式实现了这个概念?
我很高兴听到关于这方面的故事和意见。
谢谢!
发布于 2016-12-10 14:59:25
是否有关于微/宏任务的W3C规范?
W3C谈到任务队列
当用户代理要对任务排队时,它必须将给定的任务添加到相关事件循环的任务队列之一。来自一个特定任务源的所有任务(例如定时器产生的回调、用于鼠标移动的事件、为解析器排队的任务)必须始终添加到同一个任务队列中,但是来自不同任务源的任务可能被放置在不同的任务队列中。
EcmaScript2015谈到作业队列,并要求至少支持两个:
这个语言定义不知道可能的事件循环,但是可以想象一个或多个作业队列被保留用于W3C规范中提到的任务队列。浏览器将根据setTimeout任务队列规范(链接到作业队列)触发W3C回调,而承诺必须直接使用作业队列规范(而不是任务队列)。还提到代理可以将任务插入到作业队列中:
或者,实现可以选择等待某个特定于实现的代理或机制来排队新的PendingJob请求。
EcmaScript规范不强制为不同的作业队列提供服务的优先级:
此规范没有定义服务多个作业队列的顺序。ECMAScript实现可以将对作业队列的PendingJob记录的FIFO评估与对一个或多个其他作业队列的PendingJob记录的评估交织在一起。
因此,这里似乎没有严格的要求,在setTimeout任务之前应该为承诺的实现服务。但是,网络超文本应用技术工作组WHATWG在覆盖事件循环时更为具体
每个事件循环都有一个微任务队列。微任务是最初要在微任务队列中排队的任务,而不是任务队列。
2019年增加了,平均时间活HTML标准 WHATWG现在包括以下内容:
8.6微任务排队 Self.queueMicrotask(回调) 将微任务排队以运行给定的回调。
queueMicrotask(callback)方法必须对微任务排队以调用callback,如果callback抛出异常,则报告异常。queueMicrotask()方法允许作者对微任务队列调度回调。这允许它们的代码在当前执行的任务运行到完成并且JavaScript执行上下文堆栈为空之后运行,但不会将控制权返回给事件循环,例如使用setTimeout(f, 0)时就是如此。
所有的VM引擎都是这样实现的吗?
历史上,不同的浏览器实现会导致不同的执行顺序。2015年的文章可能是一个有趣的读物,可以看到它们有多么不同:
有些浏览器..。正在运行承诺回调后的
setTimeout。很可能,他们称承诺回调是一个新任务的一部分,而不是一个微任务。 Firefox和Safari正确地耗尽了单击侦听器之间的微任务队列,如突变回调所示,但承诺的排队方式似乎不同。..。对于边缘,我们已经看到它的队列承诺是错误的,但它也没有耗尽单击侦听器之间的微任务队列,而是在调用所有侦听器之后才这样做。
自那时以来,几个问题得到了解决和协调。
但是,请注意,不需要有一个微任务队列,也不需要一个宏任务队列。可以有几个队列,每个队列都有自己的优先级。
有意义的API
当然,实现您建议的两个功能并不困难:
let pushToMicroTask = f => Promise.resolve().then(f);
let pushToMacroTask = f => setTimeout(f);
pushToMacroTask(() => console.log('Macro task runs last'));
pushToMicroTask(() => console.log('Micro task runs first'));
2019,现在我们有了queueMicrotask(),有了一个本机实现。下面是一个演示,将该方法与上面基于承诺的实现进行比较:
let queuePromisetask = f => Promise.resolve().then(f);
let queueMacrotask= f => setTimeout(f);
queueMicrotask(() => console.log('Microtask 1'));
queueMacrotask(() => console.log('Macro task'));
queuePromisetask(() => console.log('Promise task'));
queueMicrotask(() => console.log('Microtask 2'));
https://stackoverflow.com/questions/41075724
复制相似问题