JS的事件循环理解

早年曾写了一篇事件循环的学习笔记,Jake Archibald: In The Loop【事件循环学习笔记】,不过这个以视屏学习为主流程,今天再写一篇,对事件循环做个补充.

一. 为什么需要事件循环

因为js是一门单线程语言,但是我们因为需要调用接口或者进行其他需要延时的操作,如果是单线程,就会阻塞整个进程.所以实现单线程非阻塞的方法就是事件循环.

在JS中任务大致分为两种:

  • 同步任务:可以立即执行,同步任务一般会直接进入到主线程中执行.
    注意: new Promise 是同步任务,可以进入主线程
  • 异步任务:异步进行的任务,例如setTimeout等等

二.宏任务和微任务

异步任务也分为两种:

  • 微任务:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
    常见微任务:promise.then,process.nextTick,MutaionObserver

  • 宏任务:时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
    常见宏任务: script(外层同步代码);setTimeout/setIntervel;setImmediate;UI rendering

事件循环,宏任务,微任务的关系在另一篇文章写了,就不再重复

看一个例子:

console.log(1)
setTimeout(()=>{
    
    
    console.log(2)
}, 0)
new Promise((resolve, reject)=>{
    
    
    console.log('new Promise')
    resolve()
}).then(()=>{
    
    
    console.log('then')
})
console.log(3)

流程如下

// 遇到 console.log(1) ,直接打印 1
// 遇到setTimeout,属于新的宏任务,进入宏任务队列,后面再执行
// 遇到 new Promise,这个是直接执行的,打印 'new Promise'
// .then 属于微任务,放入微任务队列,后面再执行
// 遇到 console.log(3) 直接打印 3
// 好了本轮宏任务执行完毕,现在去微任务列表查看是否有微任务,发现 .then 的回调,执行它,打印 'then'
// 当一次宏任务执行完,并且微任务也清空了, 再去执行新的宏任务,这里就剩一个定时器的宏任务了,执行它,打印 2

结果:1 new Promise 3 then 2

三. async和await

对于他们处理就一句话:

不管await后面跟着的是什么,await都会阻塞后面的代码, 将他们放入微任务队列中,然后执行 async外面的同步代码

async function fn1 (){
    
    
    console.log(1)
    await fn2()
    console.log(2) // 阻塞
}

async function fn2 (){
    
    
    console.log('fn2')
}

fn1()
console.log(3)

流程如下

// 1.执行fn1()时遇到 console.log(1),输出 1
// 2.执行fn2()时遇到 console.log('fn2'),输出 fn2
// 3.遇见await ,后面代码也就是 console.log(2)会被阻塞,放入微任务队列
// 4.执行 async 外面的同步代码,即 console.log(3),输出 3
// 5.主任务完成,执行微任务,即 console.log(2), 输出2

结果: 1 fn2 3 2

四. 小挑战

async function async1() {
    
    
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    
    
    console.log('async2')
}
console.log('script start') 
setTimeout(function () {
    
    
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    
    
    console.log('promise1')
    resolve()
}).then(function () {
    
    
    console.log('promise2')
})
console.log('script end')

流程如下

// 1.执行整段代码,遇到 console.log('script start') 直接打印结果,输出 script start
// 2.遇到定时器了,它是宏任务,先放着不执行
// 3.遇到 async1(),执行 async1 函数,先打印 async1 start,
// 4.遇到await 先执行 async2,打印 async2,然后阻塞下面代码(即加入微任务列表),跳出去执行同步代码
// 5.跳到 new Promise 这里,直接执行,打印 promise1,下面遇到 .then(),它是微任务,放到微任务列表等待执行
// 6.最后一行直接打印 script end
// 7.现在同步代码执行完了,开始执行微任务,打印 async1 end
// 8.继续执行下一个微任务,即执行 then 的回调,打印 promise2
//9. 上一个宏任务所有事都做完了,开始下一个宏任务,就是定时器,打印 settimeout

结果: script start、async1 start、async2、promise1、script end、async1 end、promise2、settimeout

猜你喜欢

转载自blog.csdn.net/baidu_33438652/article/details/124301864