事件循环的执行顺序:
1. 先在主线程执行所有的同步任务,形成一个执行栈
2. 在主线程之外会形成一个任务队列用来依次放置异步事件,进行排队
3. 当主线程内的所有任务执行完毕之后就会按顺序读取满足异步条件(比如定时)的任务(事件),使其进入执行栈。直至任务队列和执行栈的代码执行完毕。
1. 执行栈
在js中,当很多函数被依次调用的时候,因为js是单线程的,同一时间只能执行一个函数,怎么办?不能同时来,得排个队,排个一子队,按照顺序来,那这个一子队的顺序,即哪个函数在前,哪个函数在后,谁来记录呢?js为此专门开辟了一个内存区域,起名叫做执行栈。在执行栈里,保存着即将要执行的函数。
在同步事件中,js会从上到下依次将事件放入队列。而异步任务js并不会一直等待,而是会将这个事件挂起到另一个队列--事件队列
2.异步事件有哪些?
Promise,async,await,setTimeout,ajax,addEventListener
其中,promise是事件队列中的微任务队列,其余都是宏任务队列。微任务耗时少,故微任务比宏任务先执行。同时:promise的回调函数里面的代码都是同步,.then里的回调函数才是异步的
3. 示例:微任务和宏任务:
在上述函数中,同步先执行完毕输出2(promise里的回调函数是同步)和4之后再输出.then函数的3(虽然他也是异步并且出于settimeout();的下面,但是微任务较宏任务先执行)最后输出settimeout宏任务的1
4. 最后来一个总的示例:
setTimeout(function(){
console.log(1); //异步宏,进入事件队列 第八步
},1000);
setTimeout(function(){
console.log(2); //异步宏,进入事件队列 第七步
},0);
new Promise(function(resolve,reject){
console.log(3); //同步,进入执行栈 第一步
resolve();
}).then(()=>{
console.log(4); //异步微,进入事件队列 第五步
});
async function async1(){
console.log(5); //同步,进入执行栈 第二步
await async2(); //返回一个promise对象,异步微,进入事件队列
console.log(6); //同步,但因为await,需等到await async2();运行结束后执行 第六步
}
async function async2(){
console.log(7); //同步,async2调用后进入执行栈 第三步
}
async1();
console.log(8); //同步,进入执行栈 第四步
//35784621
读者可能混淆的是输出7之后为何不是输出6,以及6为何是在4之后输出的
原因是await async2();函数返回的是一个promise对象,属于微任务,故它会在事件队列的微任务的.then之后执行,所以6在8和4之后输出.