本文已获得原作者devinduct授权翻译。1.实验让我们做一个实验。哪个执行得更快:立即解析的Promise或立即的setTimeout(即0毫秒的setTimeout)?Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});setTimeout(functiontimeout(){console.log('Timedout!');},0);//'已解决!'//'超时!'promise.resolve(1)是一个静态函数,它返回一个立即解决的承诺。setTimeout(callback,0)延迟0毫秒执行回调函数。我们可以看到它打印出“已解决!”首先,然后打印Timeoutcompleted!,立即解决的承诺比立即设置超时更快。Promise进程是否更快,因为Promise.resolve(true).then(...)在setTimeout(...,0)之前调用?公平的问题。所以,我们稍微改变一下实验条件,先调用setTimeout(...,0):setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1)。then(functionresolve(){console.log('Resolved!');});//'Resolved!'//'Timedout!'之前调用了Promise.resolve(true).then(...)中的setTimeout(...,0)。但是,它仍然打印Resolved!在打印“超时!”之前。为什么是这样?2、事件循环和异步JS相关的问题,通过研究事件循环就可以得到解答。让我们回顾一下异步JS工作原理的主要组件。调用堆栈是一种LIFO(后进先出)结构,用于存储代码执行期间创建的执行上下文。简单的说,就是调用栈执行这些函数。WebAPI是异步操作(获取请求、承诺、计时器)及其回调等待完成的地方。**任务队列(taskqueue)是一个FIFO(先进先出)**结构,保存着准备执行的异步操作的回调。例如,超时的setTimeout()回调函数或准备执行的按钮单击事件处理程序在任务队列中排队。**作业队列(jobqueue)**是一个FIFO(先进先出)结构,用于保存准备执行的promises的回调。例如,已完成承诺的解决或拒绝回调在作业队列中排队。最后,事件循环永久监控调用栈是否为空。如果调用堆栈为空,事件循环会查看作业队列或任务队列,并将任何准备好执行的回调分派到调用堆栈上。3.作业队列和任务队列我们从事件循环的角度来看这个实验,我会一步步分析代码执行。A)调用堆栈执行setTimeout(...,0)并安排一个计时器,timeout()回调存储在WebAPI中:B)调用堆栈执行Promise.resolve(true).then(resolve)并安排一个承诺解决计划。resolved()回调存储在WebAPI中:C)promise立即resolve,计时器也立即执行。这样,定时器回调timeout()进入任务队列,promise回调resolve()进入作业队列D)现在有趣的部分来了:作业队列(微任务)比任务队列(宏任务)具有更高的优先级).事件循环从作业队列中获取承诺回调resolve()并将其放入调用堆栈。然后,调用堆栈执行承诺回调resolve():E)最后,事件循环将定时器回调timeout()从任务队列中出列到调用堆栈。然后,调用栈执行定时器回调timeout():调用栈为空,脚本执行完毕。总结一下为什么立即解决的承诺比立即执行的计时器解决得更快?由于事件循环的优先级,作业队列(存储已履行的承诺)与任务队列(存储超时的setTimeout()回调)进行比较。回调)具有更高的优先级。结束~我是小智,我去洗碗了,下次见!作者:MilosProtic译者:前端小智来源:devinduct微信公众号“大千世界”,可通过以下二维码关注。转载请联系大千世界公众号。
