彻底弄懂javascript中的异步、微任务、宏任务、Eventloop

本文深入探讨JavaScript的单线程执行机制和异步任务处理,介绍了事件循环(Event Loop)和任务队列的概念,包括宏任务与微任务的区别,并通过实例解析了执行顺序。理解这一机制对于优化JavaScript性能和编写高效的异步代码至关重要。
摘要由CSDN通过智能技术生成

概念

js是单线程的,也就代表js只能一件事情一件事情执行,那如果一件事情执行时间太久,后面要执行的就需要等待,需要等前面的事情执行完成,后面的才会执行。

所以为了解决这个问题,js委托宿主环境(浏览器)帮忙执行耗时的任务,执行完成后,在通知js去执行回调函数,而宿主环境帮我们执行的这些耗时任务也就是异步任务

js本身是无法发起异步的,但是es5之后提出了Promise可以进行异步操作

执行流程

在这里插入图片描述

  1. 主线程先判断任务类型
    • 如果是同步任务,主线程自己执行
    • 如果是异步任务,交给宿主环境(浏览器)执行
  2. 浏览器进行异步任务的执行,每个异步执行完后,会将回调放进任务队列,先执行完成的先放进任务队列,依次放入
  3. 等主线程任务全部执行完后,发现主线程没有任务可执行了,会取任务队列中的任务,由于任务队列里是依次放入进来的,所以取得时候也会先取先进来的,也就是先进先出原则
  4. 在任务队列中取出来的任务执行完后,在取下一个,依次重复,这个过程也称为eventLoop 事件轮训

宏任务

由宿主环境发起的异步:宏任务

setTimeOut、setInterval、特殊的(代码块、script)

setTimeOut
在这里插入图片描述

setInterval

在这里插入图片描述

setImmediate

在这里插入图片描述

微任务

由javascript自身发起的异步:微任务

在这里插入图片描述

在这里插入图片描述

执行顺序

  1. 先执行宏任务
  2. 宏任务执行完后看微任务队列是否有微任务
  3. 没有微任务执行下一个宏任务
  4. 有微任务将所有微任务执行
  5. 执行完微任务,执行下一个宏任务

在这里插入图片描述

练习案例

案例1:

console.log(1)
setTimeout(function(){
  console.log(2)
}, 0)
new Promise(function(resolve){
  console.log(3)
  resolve()
}).then(function(){
  console.log(4)
})
console.log(5)

答案:1、3、5、4、2

解析:

  1. 主线程判断是同步代码还是异步代码

    console.log(1)  // 同步任务
    setTimeout(function(){
      console.log(2) // 异步任务:宏任务
    }, 0)
    new Promise(function(resolve){
      console.log(3) // 同步任务
      resolve()
    }).then(function(){
      console.log(4) // 异步任务:微任务
    })
    console.log(5)  // 同步任务
    
  2. 执行同步任务

    console.log(1)  // 同步任务
    console.log(3) // 同步任务
    console.log(5)  // 同步任务
    
  3. 执行异步任务:微任务

    console.log(4) // 异步任务:微任务
    
  4. 执行异步任务:宏任务

    console.log(2) // 异步任务:宏任务
    

案例2:

注意点:await的执行顺序为从右到左,会阻塞后面的代码执行,但并不是直接阻塞await的表达式

await下面(下面不是右面)的代码可以理解为promise.then(function(){ 回调执行的 })

async function async1() {
  console.log('async1 start')
  await async2()
  // await后面的代码可以理解为promise.then(function(){ 回调执行的 })
  console.log('async1 end')
}

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

console.log('script start')
setTimeout(function() {
  console.log('setTimeout')
}, 0)

async1()

console.log('script end')

答案:script start、async1 start、async2、script end、async1 end、setTimeout

解析:

  1. 主线程判断同步异步

    async function async1() {
      console.log('async1 start')
      await async2() // 同步任务
      // await后面的代码可以理解为promise.then(function(){ 回调执行的 })
      console.log('async1 end') // 异步任务:微任务
    }
    
    async function async2() {
      console.log('async2')
    }
    console.log('script start') // 同步任务
    setTimeout(function() {
      console.log('setTimeout') // 异步任务:宏任务
    }, 0)
    
    async1() // 同步任务
    
    console.log('script end') // 同步任务
    
  2. 执行同步任务

    console.log('script start')
    console.log('async1 start')
    console.log('async2')
    console.log('script end')
    
  3. 执行异步任务:微任务

    console.log('async1 end')
    console.log('setTimeout')
    

案例3:

console.log(1)
setTimeout(function(){
  console.log(2)
}, 2000)
new Promise(function(resolve){
  console.log(3)
  resolve()
}).then(function(){
  console.log(4)
})

setTimeout(function(){
  console.log(5)
  new Promise(function(resolve){
    console.log(6)
    resolve()
  }).then(function(){
    console.log(7)
  })
}, 3000)

setTimeout(function(){
  console.log(8)
  new Promise(function(resolve){
    console.log(9)
    resolve()
  }).then(function(){
    console.log(10)
  })
}, 1000)

答案:1、3、4、8、9、10、2、5、6、7

解析:

  1. 区分同步任务和异步任务

    console.log(1) // 同步任务
    setTimeout(function(){
      console.log(2) // 异步任务
    }, 2000)
    new Promise(function(resolve){
      console.log(3) // 同步任务
      resolve()
    }).then(function(){
      console.log(4) // 异步任务
    })
    
    setTimeout(function(){
      console.log(5) // 异步任务
      new Promise(function(resolve){
        console.log(6)
        resolve()
      }).then(function(){
        console.log(7)
      })
    }, 3000)
    
    setTimeout(function(){
      console.log(8) // 异步任务
      new Promise(function(resolve){
        console.log(9)
        resolve()
      }).then(function(){
        console.log(10)
      })
    }, 1000)
    
  2. 执行同步任务

    console.log(1)
    console.log(3)
    
  3. 异步任务添加到不同任务队列中

    微任务添加到微任务队列[ console.log(4) ]

    new Promise(function(resolve){
      console.log(3)
      resolve()
    }).then(function(){
      console.log(4) // 微任务
    })
    

    宏任务

    由宿主发起异步,异步完成将回调放入宏任务队列

    setTimeout(function(){
      console.log(2) // 异步任务
    }, 2000)
    
    setTimeout(function(){
      console.log(5) // 异步任务
      new Promise(function(resolve){
        console.log(6)
        resolve()
      }).then(function(){
        console.log(7)
      })
    }, 3000)
    
    setTimeout(function(){
      console.log(8) // 异步任务
      new Promise(function(resolve){
        console.log(9)
        resolve()
      }).then(function(){
        console.log(10)
      })
    }, 1000)
    
    

    进入宏任务队列

    // 宏任务1:
    function(){
      console.log(8) // 异步任务
      new Promise(function(resolve){
        console.log(9)
        resolve()
      }).then(function(){
        console.log(10)
      })
    }
    // 宏任务2:
    function(){
      console.log(2) // 异步任务
    }
    
    // 宏任务3:
    function(){
      console.log(5) // 异步任务
      new Promise(function(resolve){
        console.log(6)
        resolve()
      }).then(function(){
        console.log(7)
      })
    }
    
  4. 执行微任务[]

    console.log(4) 
    
  5. 微任务已全部执行完成,接下来执行下一个宏任务

    // 宏任务1:
    function(){
      console.log(8)
      new Promise(function(resolve){
        console.log(9)
        resolve()
      }).then(function(){
        console.log(10) // 进入微任务
      })
    }
    
    console.log(8)
    console.log(9)
    
  6. console.log(10)进入微任务:[console.log(10)]

    console.log(10) // 微任务[]
    
  7. 微任务空,执行下一个宏任务

    // 宏任务2:
    function(){
      console.log(2) // 异步任务
    }
    
    console.log(2)
    
  8. 微任务中还是空,继续执行下一个宏任务

    function(){
      console.log(5) // 异步任务
      new Promise(function(resolve){
        console.log(6)
        resolve()
      }).then(function(){
        console.log(7) // 进入微任务
      })
    }
    
    console.log(5)
    console.log(6)
    
  9. 微任务中有[console.log(7)]

    console.log(7)
    
  10. 最后微任务清空,宏任务也清空

  • 11
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值