前端 js 异步流程

异步流程

概念

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. 最后微任务清空,宏任务也清空

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340