当前位置: 首页 > 科技观察

为什么Promis比setTimeout()快?

时间:2023-03-12 21:45:51 科技观察

实验先来做个实验:看看执行立即解析的Promis和0毫秒超时执行哪个更快?Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});setTimeout(functiontimeout(){console.log('Timedout!');},0);//日志'Resolved!'//logs'Timedout!'Promise.resolve(1)是一个静态函数,它返回一个立即解决的承诺。setTimeout(callback,0)以0毫秒的延迟执行回调。打开执行并检查控制台。您会看到日志打印“已解决!”其次是“超时完成!”。立即解决的承诺比立即超时解决得更快。是不是因为在setTimeout(...,0)之前调用了Promise.resolve(true).then(...),所以promise的处理会更快一些?然后我们修改实验条件,先调用setTimeout(...,0):setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});//logs'Resolved!'//logs'Timedout!'执行看控制台,结果是一样的!虽然之前调用了Promise.resolve(true).then(...)中的setTimeout(...,0),但是'Resolved!'仍在“超时!”之前打印。实验表明,立即解决的承诺会在立即超时之前解决。所以。..这是为什么?关于事件循环与异步JavaScript的问题可以通过探索事件循环来回答。让我们首先回顾一下异步JavaScript的工作原理。空的事件循环调用栈(callstack)是一种LIFO(后进先出)结构,用于存放代码执行过程中创建的执行上下文。简而言之,调用堆栈执行函数。WebAPI是异步操作(获取请求、承诺、计时器),回调等待这里的工作完成。**任务队列(taskqueue)**是一个FIFO(先进先出)结构,包含了准备执行的异步操作的回调。例如,超时的setTimeout()回调(准备执行)进入任务队列。作业队列是一个FIFO(先进先出)结构,其中包含对准备好履行的承诺的回调。例如,将解决或拒绝回调放入工作队列。最后,事件循环(eventloop)会一直监视调用栈是否为空。如果调用堆栈为空,事件循环将在工作队列或任务队列中查找并将准备好执行的回调出列到调用堆栈中。WorkQueue和TaskQueue我们从事件循环的角度来看一下前面的实验。我一步步分析代码的执行。(1)调用堆栈执行setTimeout(...,0)并“安排”一个定时器。timeout()回调存储在WebAPI中:setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});EventLoop(2)调用堆栈执行Promise.resolve(true).then(resolve)并“安排”一个promisetoresolve。resolved()回调存储在WebAPI中:setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});EventLoop(3)promise立即resolve,计时器立即到期。此时定时器回调timeout()“入队”到任务队列,promise回调resolve()“入队”到工作队列:事件循环(4)这里是最有意思的部分:事件循环优先级使工作在优先任务之前排队。事件循环从工作队列中取出promise回调resolve()并将其放入调用堆栈,然后调用堆栈执行promise回调resolve():setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1).then(functionresolve(){console.log('Resolved!');});'Resolved!'被记录到控制台。事件循环(5)最后,事件循环将定时器回调timeout()从任务队列中移除并放到调用堆栈中。然后调用栈执行定时器回调timeout():setTimeout(functiontimeout(){console.log('Timedout!');},0);Promise.resolve(1).then(functionresolve(){console.log('已解决!');});'超时!被打印到控制台。此时EventLoop调用栈为空。脚本执行完成。总之,为什么立即解决的承诺比立即计时器处理得更快?这是由于事件循环的“优先级”使得任务队列中的任务(存储已履行承诺的回调)从任务队列中的任务队列(存储超时的setTimeout()回调)中出队。