前端 js 异步流程

发布于:2023-01-06 ⋅ 阅读:(343) ⋅ 点赞:(0)

异步流程

概念

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)
    

  ```js
  console.log(2)
  1. 微任务中还是空,继续执行下一个宏任务

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

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

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到