面试的时候有人问我
“有没有可能让一段代码被调度为立即执行-即跳过队列-而不将其放在事件循环队列的末尾”。
最初我以为这是由requestIdleCallback
完成的(正如我最近读到的关于React Fiber的文章),但在检查了requestIdleCallback
文档后,我不确定这是否是它的实际工作方式,即当当前调用堆栈为空并且调用了requestIdleCallback
时,忽略引擎事件队列中的内容并运行回调。
所以...到底有没有可能?
面试的时候有人问我
“有没有可能让一段代码被调度为立即执行-即跳过队列-而不将其放在事件循环队列的末尾”。
最初我以为这是由requestIdleCallback
完成的(正如我最近读到的关于React Fiber的文章),但在检查了requestIdleCallback
文档后,我不确定这是否是它的实际工作方式,即当当前调用堆栈为空并且调用了requestIdleCallback
时,忽略引擎事件队列中的内容并运行回调。
所以...到底有没有可能?
3条答案
按热度按时间6za6bjd01#
是的,这是可能的,这甚至正是 * 队列微任务 * 任务应该做的事情:在当前作业队列的末尾,即在当前事件循环结束之前,推送新的微任务。
这可以通过全新的 * Window.queueMicrotask()* 方法来实现(如果我没有弄错的话,目前只有Webkit & Blink支持该方法)。
但即使在不支持这种方法的浏览器中,我们也可以很长时间地访问其他方法,这些方法将“* 排队微任务 *”。
首先,
Promise.resolve
的回调将作为一个微任务排队,所以我们也可以这样做。但是,即使在Promises之前,通过使用MutationObserver API,已经可以 * 排队微任务 *,因为突变记录必须作为微任务排队。
一个三个三个一个
但要注意,这也意味着即使这些方法是异步的,也可以创建无限循环,因为事件循环永远不会到达其终点。
对于
requestIdleCallback
所做的事情,它正在等待浏览器不再做任何事情,这可能会出现在相当多的事件循环中。qgelzfjb2#
我宁愿说“不”,因为JS运行时的工作方式,你不能从JS代码中改变它。
运行时处理按年龄排序的队列中的所有事件和任务(最旧的动作/任务/等首先被处理),并且运行时“运行到完成”(意味着它在运行下一个任务之前从头到尾处理每个任务)。
例如,如果您编写
setTimeout( <FUNCTION> , 0)
,函数 * 不会立即执行 * -相反,浏览器会将消息推送到队列并 * 尽可能快地处理它 。即使运行时在这一点上没有做任何其他事情,该函数以几毫秒的延迟执行(注意, 中传递的数字不能保证是函数运行的确切时间 * -它类似于 * 函数运行前经过 * 的保证时间量)。(支持)。MDN
更新以上 * 对于Nodejs* 并不完全正确。在Node中,使用
process.nextTick
,您可以将一个action * 放在队列的前面 。但是,如果事件循环已经处理了另一个任务,它不会立即被处理。因此,正确的答案应该是“是的, 但只有当您的代码运行在Nodejs上 *,可以将一个任务放在队列的开头。但是仍然不能保证它会立即运行。ljsrvy3e3#
由于事件循环只处理队列中的超时,因此这应该在Node和浏览器上都有效: