我一直在使用Javascript,我理解javascript-event-loop是如何工作的。但是,我遇到了一个对我来说没有意义的案例。 请考虑以下代码:
setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');
我期待这个输出:
3
1
2
但是,我在chrome js控制台上运行它,我得到以下内容:
3
2
1
问题:不应该“Promise.resolve()。then(fn)”要么立即调用函数,要么将函数执行过程插入到事件循环的末尾 - 'setTimeout'的工作方式 - ,有什么我想念的吗?
答案 0 :(得分:3)
浏览器实现多个作业/任务队列。 The spec requires implementations to maintain two queues:
很可能还有一个TimerQueue(HTML DOM任务队列),它也适用于HTML DOM Level 2 Timer规范。这些是在运行时填充的每个FIFO队列,最终是the event loop queue。按照您的代码示例:
setTimeout(()=> console.log('1'));
Promise.resolve('whatever').then(()=>console.log('2'));
console.log('3');
一旦堆栈为空,每个队列将排空直到空。在您的示例中,Promise队列首先清空,然后TimerQueue清空。
通过稍微扩展您的示例可以进一步证明这一点:
setTimeout(()=> console.log('second from final')); // <-- first item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('2')); //<-- first time in PromiseQueue
setTimeout(()=> console.log('just prior to final')); // <-- second item in TimerQueue
Promise.resolve('whatever').then(()=>console.log('1')); //<-- second item in PromiseQueue
setTimeout(()=> console.log('final')); // <-- third item in ScriptQueue
console.log('3'); // <-- synchrounous function call placed onto the stack, executed immediately
您应该注意执行顺序不保证。规范不定义队列的执行顺序:
此规范未定义多个Job的顺序 队列服务。 ECMAScript实现可以交织 用于评估作业队列的PendingJob记录的FIFO评估 评估一个或多个其他作业队列的PendingJob记录。
修改强>
在与Bergi讨论(下面)之后,我已经表明浏览器实现可能也会创建其他队列。与此帖相关的最可能的队列是TimerQueue作为任务队列,其中包含HTML DOM规范的计时器任务。
答案 1 :(得分:0)
setTimeout表现为细微的规则集。例如,在多个浏览器上,最小超时为4ms, not 0ms。
你是正确的,Promise不会立即执行,但会等待一个干净的堆栈运行。
还有一些技巧,比如添加一个标签来强行将某些东西撞到事件循环的顶部。请参阅setImmediate针对浏览器的polyfill