最近在面试中遇到一道关于JS执行顺序的题。问题比较基础,但如果不熟悉JS,还是很容易答不上来的。再次记录分析面试题,希望对大家有所帮助。asyncfunctionasync1(){console.log("async1start");等待async2();console.log("async1结束");}异步函数async2(){console.log("async2");}安慰。日志(“js开始”);setTimeout(function(){console.log("超时");},0);异步1();新的承诺(函数(解决){console.log(“承诺”);解决();})。然后(函数(){console.log(“然后”);});console.log("js结束");话不多说,先上结果//控制台输出结果"jsstart""async1start""async2""promise""jsend""async1end""then""timeout"宏任务和微任务,不过没关系,看完这篇文章你就明白了。如果你想完全理解上面的话题,你还需要理解JS的两个概念,是的,宏任务和微任务。首先官方肯定知道JS是单线程的。实现异步的方法就是timer和es6+中出现的promise/async。现在问题来了。自从es6中新的异步方法,相比之前的timer,异步先执行呢?宏任务(macro)任务可以理解为每段代码都是一个宏任务,没错,JS的主程序也是一个宏任务。同时,两个定时器的异步部分也是一个宏任务。Microtaskmicrotask可以理解为当前任务执行结束后立即执行的任务。即主程序执行完毕后立即执行的部分。es6+中出现的Promise和async都是微任务。这里要记住的一件事是微任务的优先级高于宏任务。程序执行顺序1.主程序因为js是单线程的,同时只能执行一段代码,所以先执行JS的主程序。前面说过主程序是宏任务,微任务的优先级高于宏任务,那为什么要先执行主程序的宏任务呢?这是因为:没有构建微任务的主程序,怎么会出现微任务呢?没有微任务的出现,当然是找到了主程序的宏任务,所以优先级的说法没有错。2.检查是否有异步任务。上一个任务执行完成后,程序会搜索是否有需要执行的微任务。如果有,微任务将首先执行。没有微任务但是有宏任务,执行宏任务。没有任务,代码就不会执行。3、微任务微任务代码执行和普通JS代码执行没有区别,从上到下编译执行!!!执行完成后,会跳回第二步。4.宏任务宏任务代码执行和普通JS代码执行没有区别,都是从上到下编译执行!!!执行完成后,会跳回第二步。回答问题,大家在做这类题的时候,也可以像我一样在旁边记录一个宏任务库和微任务库,按照上面的顺序一步步来,就对了!!!1.主程序-asyncasync1程序声明了异步async异步函数async1。当一个函数没有被调用时,函数内容的代码不会被编译执行,所以第一步不输出内容。Microtask:EmptyMacrotask:Empty2.Mainprogram-asyncasync2这里也只是定义了异步函数async2,所以这一步没有任何输出Microtask:EmptyMacrotask:Empty3.Mainprogram-console.log程序已经执行完毕console.log,没有异步,所以直接执行,控制台输出“jsstart”。Microtask:EmptyMacrotask:Empty4.主程序——setTimeout程序终于来到了第一个异步部分setTimeout。它不会立即执行,而是要等到所有的主程序和它之前的异步任务都执行完后才会执行。在这里他将被添加到宏任务队列中。Microtask:EmptyMacrotask:setTimeout5,mainprogram-async1()程序执行async1的函数调用,不存在异步,所以程序会编译执行async1的内部部分。microtask:emptymacrotask:setTimeout5.1,async1-console.logasync异步函数是这样的,当函数被调用时,程序会正常立即执行,但是当遇到await关键字时,下一行的语句await会作为一个microtask任务被添加到microtask队列中,await后面的部分也会被立即执行。因此,这条console.log会立即执行,控制台输出"async1start"microtask:Emptymacrotask:setTimeout5.2,async1-awaitasync2()await语句后的内容会立即执行,下一行和之后的内容会被加入到microtask队列中,于是再次进入async2,在microtask队列中加入一个microtask。Microtask:async1Macrotask:setTimeout详见前端高级面试题5.2.1答案,async2——console.logconsole.log立即执行,没有异步部分,所以控制台输出“async2”。至此,async1中的同步内容执行完毕。Microtask:async1Macrotask:setTimeout6,mainprogram-Promisepromise就是这样异步的,构建实例时传入的函数内容被立即编译执行,然后加入到microtask队列中。微任务:async1宏任务:setTimeout6.1,Promise-console.logconsole.log立即执行,没有异步部分。控制台输出“primise”。Microtask:async1macrotask:setTimeout6.2,Promise-resolveresolve立即执行,但随后加入微任务队列。微任务:async1Promise-then宏任务:setTimeout7,主程序-console.logconsole.log立即执行,没有异步部分。控制台输出“jsend”。至此,主程序已经执行完毕,接下来执行上面的第二步。Microtask:async1Promise-thenmacrotask:setTimeout8,microtaskasync1-console.log检测到有microtask,执行microtask。console.log立即执行,没有异步部分。控制台输出“async1end”。同时删除微任务队列中对应的任务,再次返回第二步。Microtask:Promise-thenMacrotask:setTimeout9,microtaskPromise-then-console.log检测到有microtask,执行microtask。console.log立即执行,没有异步部分。控制台输出“然后”。同时删除微任务队列中对应的任务,再次返回第二步。Microtask:emptymacrotask:setTimeout8和9步骤在不同的浏览器版本中执行顺序可能不同,所以不用担心这两个步骤的先后顺序。10、宏任务setTimeout-console.log检测到没有微任务,执行宏任务队列。console.log立即执行,没有异步部分。控制台输出“超时”。同时删除宏任务队列中对应的任务,再次返回第二步。Microtask:EmptyMacrotask:Empty11.Endofexecution检测到所有任务队列都执行完毕,代码执行结束。综上所述,面试题已经解释完毕。内容比较长,但是也比较详细。大家遇到类似的题,可以按照我的方法去做,基本不会出错。
