javascript中microtask和macrotask实例分析-mile米乐体育
javascript中microtask和macrotask实例分析
这篇文章主要讲解了“javascript中microtask和macrotask实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“javascript中microtask和macrotask实例分析”吧!
首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容?
asyncfunctionasync1(){console.log('async1start');awaitasync2();console.log('async1end');}asyncfunctionasync2(){console.log('async2start');returnnewpromise((resolve,reject)=>{resolve();console.log('async2promise');})}console.log('scriptstart');settimeout(function(){console.log('settimeout');},0);async1();newpromise(function(resolve){console.log('promise1');resolve();}).then(function(){console.log('promise2');}).then(function(){console.log('promise3');});console.log('scriptend')
说实话,真正能在面试中把这道题目答对的前端工程师凤毛麟角。我们先来瞧一下答案吧。把以上代码存到test.js文件中,并用node执行一下,结果如下:
如果把以上代码贴到一个网页中的script标签里面,然后打开这个网页,再打开控制台,可以看到如下输出(chrome 64位63.0.3239.84):
结果和node打印的一模一样。那么为什么是这个顺序呢?
我们都知道js的单线程特性(html5的web worker不算在内~)以及良好的异步支持。在单线程的前提下,异步任务到底什么时候开始执行,其实是有两个队列来进行管理,即macrotask和microtask(只有一个字母的差距,不要认错……)。在当前正在执行的线程中,如果碰到属于macrotask的异步任务,则放入macrotask队列;碰到microtask的异步任务则放入microtask队列。注意这里只是把任务放入队列,并不会执行它。等到当前主线程任务执行完毕之后,会依次从microtask队列中取出任务执行,在执行期间当然还是遵循碰到异步任务放入相应队列的原则。等到microtask任务全部执行过了,此时再从macrotask队列中取出一个任务执行。
属于macrotask的任务有:
settimeout,setinteveral,script标签,i/o,ui渲染
属于microtask的任务有:
promise,async/await,process.nexttick,object.observe,mutationobserver
(事实上,即使同样是microtask,内部也是有优先级的差别的,例如nodejs的实现上,process.nexttick比promise要先执行。相关问题可以瞧瞧这个连接:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ 。反正我瞧到一半就放弃了,好在async/await和promise没有优先级差别)
然后我们来分析一下本题中的执行顺序:
【1】第15行执行,打印出script start
【2】第16至18行,把回调任务放入macrotask (目前macrotask:第16行settimeout,microtask:空)
【3】第20行,执行async1函数,先打印出第2行的async1 start
【4】第3行的async2先执行,打印出第8行的async2 start
【5】第9行至第12行遇到promise,先打印出第11行的async2 promise(注意不管你resolve写在new promise的函数什么位置,都跟写到最后一句一样!)
【6】第3行的async2返回了promise,并且async2前面有await修饰,因此后面第4行的任务被放到microtask(目前macrotask:第16行settimeout,microtask:第4行)
【7】第22至25行,打印出promise1,并把第26行放入microtask,注意第28行还没执行到,所以这行什么都不做(目前macrotask:第16行settimeout,microtask:第4行,第26行)
【8】第30行打印script end(目前macrotask:第16行settimeout,microtask:第4行,第26行)
【9】脚本主线程执行结束,现在拿出来一个microtask,即第4行,打印async1 end(目前macrotask:第16行settimeout,microtask:第26行)
【10】再拿出来一个microtask,即第26行,打印promise2,此时由于第26行后面跟着then,所以把第28行插入microtask(目前macrotask:第16行settimeout,microtask:第28行)
【11】再拿出来一个microtask,即第28行,打印promise3(目前macrotask:第16行的settimeout,microtask:空)
【12】microtask没有了,执行下一个macrotask,即第16行的settimeout,打印settimeout,结束
需要注意的是,以下两种写法,效果是一模一样的(resolve的位置无所谓):
写法1:newpromise((resolve,reject)=>{console.log('1111');resolve();console.log('2222');});写法2:newpromise((resolve,reject)=>{console.log('1111');console.log('2222');resolve();});
另外,对于promise的链式调用,如new promise(....).then(...).then(...)....,一次只放第一个then的内容进入microtask,等第一个then执行的时候,会把第二个then放入microtask,而不是一次把两个then都放进去。
感谢各位的阅读,以上就是“javascript中microtask和macrotask实例分析”的内容了,经过本文的学习后,相信大家对javascript中microtask和macrotask实例分析这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是恰卡编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!