异步编程中最难的,任务队列分类和事件循环
任务指的是js代码中的运行的代码。fn( )代表了fn任务的运行,脚本也是一个任务,计时器的运行也是一个任务,peomise也是一个任务
【任务分为同步的任务和异步的任务】
【异步任务分两种:宏任务和微任务】
同步任务:
function fn( )
var a=new Array( )
var b=fn( )
异步任务:
setTimeout(fn,100
p1.then(fn)
conlsosle.log(123)
队列优先级:异步宏任务>异步微任务
举例:
第一行是同步任务先执行;第二行是一个异步宏任务,不会马上执行会开一个新子线程运行;第三行也是一个异步宏任务,也不会马上执行会将其放入新子线程中在上一个异步任务后面排队;第四行是一个同步任务,马上执行n1执行1000次以后执行第五行;第五行也是一个异步微任务,不会马上执行会将其放入新子线程中;第六行是一个同步任务,马上执行打印5。同步任务执行完毕后再执行异步任务,异步任务是先执行宏任务在执行微任务,但是第五行的then函数是属于第一轮的宏任务中的微任务,所以要先执行完才能执行下一轮的宏任务,所以3要先于1,2打印。第一轮的宏任务执行完毕后,执行第二轮的宏任务就是第二行和第三行,他们的执行循序是谁先打印就看谁先运行完毕,第二行和第三行的执行时间结束一致,但是第三行先于第四行,所以先打印1,再打印2.所以打印顺序是4,5,3,1,2
这就出现了任务队列===>任务开启后:内部执行的时候可能会有新的任务,执行顺序,先执行宏任务,那些属于宏任务呢?脚本任务。首先脚本运行就执行第一个宏任务:先执行同步任务;添加新的任务到对列中,添加新的异步微任务;执行异步微任务。在执行下一轮的宏任务,重复上述步骤,知道执行完所有的代码。
事件循环:
同步>宏任务>微任务>下一轮的宏>下一轮的微
做个小练习吧:
分析:
首先主线程中只有一个任务就是脚本任务,脚本任务开启就开始跑代码。首先执行第24行,第24行是一个同步任务直接执行,打印4;在执行第25行,第25-32行是一个异步宏任务,不会马上执行,将其放入一个新的子线程中等待;接着跑代码,执行33行,33-40行也是一个异步宏任务,不执行将其放入刚刚那个新的子线程在前面那个异步任务后面等待;执行41-43行,是一个同步任务,马上执行,n1执行1000次后接着跑下面的代码;执行44行,是一个异步微任务任务,不会马上执行,将其放入一个新的子线程中等待;最后执行第45行,是个同步任务,立马执行打印5.
第一轮的宏任务执行完毕,开始执行第一轮的微任务。执行第44行,打印3.
开始执行第二轮宏任务,执行第25-32行,执行26行,是一个异步宏任务,不会马上执行,将其放入子线程中等待;执行27行,是一个同步任务,立即运行打印1;执行28-30行,是一个同步任务,运行循环n1 1000次;接着执行31-32行,是一个异步微任务,不会马上执行,将其放入子线程中等待。
第二轮的宏任务执行完毕,开始执行第二轮的微任务。执行31-32行,打印7.
开始执行下一个宏任务,执行第34行,是一个异步宏任务,不会马上执行,将其放入子线程中等待;执行35-37行,是一个同步任务,运行循环n1 1000次;执行38行,是一个异步微任务,不会马上执行,将其放入子线程中等待。执行39行,是同步任务立即执行,打印2.
这一轮的宏任务执行完毕,开始执行这一轮的微任务,执行38行打印8.
由于25-32行和33-40行都是异步宏任务,而他们的执行完成时间都是一样的,所以按照代码的先后打印。
最后执行子线程中剩余的两个异步宏任务,因为第26行的异步宏任务等待时间少于,第34行的异步宏任务,所以先打印6,再打印2