宏任务与微任务
Event Loop:事件循环
我们都知道 Js 是单线程的,但是一些高耗时操作就带来了进程阻塞问题。为了解决这个问题,Js 有两种任务的执行模式:同步模式(Synchronous)和异步模式(Asynchronous)
异步模式
在异步模式下,创建异步任务主要分为宏任务与微任务两种,宏任务是由宿主(浏览器、Node)发起的,而微任务由 JS 自身发起。微任务比宏任务的执行时间要早。
异步任务:不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以这种机制被叫做事件循环(Event Loop)
任务队列和Event Loop(事件循环)
1)所有的同步任务都在主线程上执行,行成一个执行栈。
2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。
3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列再执行宏任务队列。
4)重复上面三步。
只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。
宏任务:SettimeOut()、setInterval、I/O、script(整体代码块)、DOM事件、Ajax
微任务:Promise.[ then/catch/finally ]、async/await
注意:Promise本身是属于同步任务
栗子:
setTimeout(function(){
console.log('setTimeout')
},0)
//同步
console.log('script start')
async function async1(){
//同步
console.log('async1 start');
await async2()
//异步
console.log('async1 end')
}
async function async2(){
//同步
console.log('async2 end')
}
//微任务
new Promise(function(resolve){
//同步
console.log('promise')
for (var i = 0; i <10000; i++) {
if (i === 10) {
console.log("3")
}
i == 9999 && resolve('4')
}
resolve();
}).then(function(val){
console.log(val)
//异步
console.log('promise1')
}).then(function(res){
console.log(res)
console.log('promise2')
})
//微任务
async1();
//同步
console.log('script end')
执行步骤
1) 事件任务从宏任务(macrostack)队列开始,此时宏任务队列中只有一个script(整体代码)任务
,从宏任务队列中取一个任务来执行
2)首先遇到 setTimeout 添加到宏任务队列中
3) 执行同步代码 console.log('script start') 输出 script start
4)遇到 两个 async(异步)Function 未调用 暂不放入微任务队列。
5)遇到 new Promise() 因为promise属于同步任务 进入执行
5.1)执行console.log('promise') 输出 promise
5.2)执行for循环,i=1时 执行console.log("3") 输出 3
5.3)执行for循环,i=9999时 执行resolve('4'), 触发.then, .then属于微任务 放入微任务队列
5.4)执行resolve()触发.then, .then属于微任务 放入微任务队列
6)遇到 async1() 同步调用, 进入async1()
6.1)执行console.log('async1 start'); 输出 async1 start
6.2)执行await async2() 由于await 所以是同步执行 进入async2()
6.2.1) 执行console.log('async2 end'); 输出 async2 end
6.3)遇到 console.log('async1 end') 属于异步 加入微任务队列
7) 遇到console.log('script end') 输出 script end 到此同步任务执行完毕
8) 取出微任务队列中 所有内容 .then和 asyn加入的console.log('async1 end') 执行
8.1) 先执行resolve('4')的.then 输出 4 promise1
8.2) 执行resolve()的.then 输出 undefined promise2
8.2) 执行asyn加入的console.log('async1 end') 输出 async1 end (async1 输出可能会在undefined之前) 到此微任务执行完毕
9) 去除宏任务,按照存放顺序
9.1) 执行 settimeout() 输出 setTimeout