导读

javascript是一门单线程语言,一切javascript版的多线程都是用单线程模拟出来的,所以代码执行还是顺序执行的原则,只不过编写的顺序被执行环境重新“编排”了一下而已。

执行过程中,我们把任务分为同步任务和异步任务,而异步任务又分为宏任务,微任务。
一般顺序:同步->微任务->宏任务

  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

node环境与浏览器环境区别:(这里先写出区别,下面做详细介绍,具体不同环境为什么异步输出不同。)

node环境中,任务全部出队,并执行。

浏览器环境,出队一个任务,并执行。

任务入队规则

异步任务队列分为宏任务队列,微任务队列。

代码顺序执行,碰到异步代码后放入对应队列内。第一遍代码执行完毕后,会取出微任务队列内的代码继续执行,执行完后再取出宏任务队列内的代码继续执行。以此反复执行直到最后执行完所有任务。

运用递归思想描述

function 代码执行(任务){任务执行,异步的代码入队代码执行(微任务出队)代码执行(宏任务出队)
}

这里说明一下:由于node环境下的事件监听依赖libuv与前端环境不完全相同,输出会有差异。

主要原因:虽然规则相同,但是入队的顺序会有差异,出队任务数量也有不同,所以输出会有差异

实例演示

下面结合实例,将在node端和浏览器端分别说明其差异性。

使用代码:

    console.log('1');setTimeout(function() { //timeout1console.log('2');new Promise(function(resolve) {console.log('4');setTimeout(function(){//timeout2console.log('5');resolve()//promise1})}).then(function() {console.log('6');})})new Promise(function(resolve) {console.log('8');resolve();//promise2}).then(function() {console.log('9');})setTimeout(function() { //timeout3console.log('10');new Promise(function(resolve) {console.log('12');resolve();//promise3}).then(function() {console.log('13');})setTimeout(function(){//timeout4console.log('14')new Promise(function(resolve){console.log('15')resolve() //promise4}).then(function() {console.log('16');})})})
浏览器端:

这里建议打开两个页面,一边对照代码一边看一下步骤。

第一次执行代码:输出1,timeout1压入宏队列,输出8,promise2压入微队列,timeout3压入宏任务队列。

//在浏览器端,边执行代码,边把异步代码加入对应队列,这一次执行都是同步代码。

//宏任务队列内[timeout1,timeout3],微任务队列[promise2]

第二次执行代码(promise2出队):输出9

//微任务队列优先级高,先执行微任务,浏览器端只有一个任务出队并执行。

//宏任务队列内[timeout1,timeout3],微任务队列[]

第三次执行代码(timeout1出队):输出2,输出4,timeout2压入宏队。

//宏任务队列内[timeout3,timeout2],微任务队列[]

第四次执行代码(timeout3出队):输出10,输出12,promise3压入微队列,timeout4压入宏队列。

//宏任务队列内[timeout2,timeout4],微任务队列[promise3]

第五次执行代码(promise3出队):输出13。

//宏任务队列内[timeout2,timeout4],微任务队列[]

第六次执行代码(timeout2出队):输出5,promise1压入微队列。

//宏任务队列内[timeout4],微任务队列[promise1]

第七次执行代码(promise1出队):输出6。

//宏任务队列内[timeout4],微任务队列[]

第八次执行代码(timeout4出队):输出14,输出15,promise4压入微队列。

//宏任务队列内[],微任务队列[promise4]

第九次执行代码(promise4出队):输出16。

//宏任务队列内[],微任务队列[]

顺序为:1,8,9,2,4,10,12,13,5,6,14,15,16

node端

第一次执行代码:输出1,timeout1压入宏队列,输出8,promise2压入微队列,timeout3压入宏任务队列。

//第一次执行node端和浏览器端二者相同。

//宏任务队列内[timeout1,timeout3],微任务队列[promise2]

第二次执行代码(promise2出队):输出9

//二者相同。

//宏任务队列内[timeout1,timeout3],微任务队列[]

第三次执行代码([timeout1,timeout3出队):输出2,输出4,timeout2压入宏队列,输出10,输出12,promise3压入微队列,timeout4压入宏队列。

//这里我们可以看到,node与浏览器不同之处,timeout1,timeout3一起出队,所以内部的同等级(同步代码)就一起执行了。node环境的这一次执行完成了浏览器多次执行步骤。

//宏任务队列内[timeout2,timeout4],微任务队列[promise3]

第四次执行代码(promise3出队):输出13。

//宏任务队列内[timeout2,timeout4],微任务队列[]

第五次执行代码(timeout2,timeout4出队):输出5,promise1压入微队列,输出14,输出15,promise4压入微队列。

//在这里输出数值与浏览器端开始有差异。

//宏任务队列内[],微任务队列[promise1,promise4]

第六次执行代码(promise1,promise4出队):输出6,输出16。

//宏任务队列内[],微任务队列[]

顺序为:1,8,9,2,4,10,12,13,5,14,15,6,16

总结:

简单结构的代码,一般执行顺序:同步->微任务->宏任务。复杂结构代码,微任务优先级大于宏任务优先级。同步代码边执行,边把异步任务入队,然后系统选择出队的任务再一次新一轮执行。

node环境与浏览器环境区别:node环境中,任务全部出队,并执行。浏览器环境,出队一个任务,并执行。

备注1

console.log("11")
new Promise(function(resolve) {console.log('12');//这里代码属于同步代码,只有then内代码才是异步代码,同上面“console.log("11")”代码段一起顺序执行。resolve();}).then(function() {console.log('13');})

备注2

在node环境中process.nextTick()比Promise优先级高,所以优先执行

new Promise(function(resolve) {console.log('7');resolve();
}).then(function() {console.log('8')
})
process.nextTick(function() {console.log('6');
})
//7,6,8

备注3

这一次,彻底弄懂 JavaScript 执行机制:https://juejin.im/post/59e85eebf265da430d571f89

异步执行顺序——宏任务与微任务不同环境下的出队规则相关推荐

  1. 一篇文章理解JS中同步任务和异步任务以及宏任务与微任务的原理和执行机制

    前言: javascript是一种单线程编程语言, 一般来说它的执行顺序是按照从上到下执行,但是有些特殊情况则会改变这样的执行顺序,我们需要理解和掌握其中的原理,需要了解同步任务和异步任务以及宏任务和 ...

  2. javascript的异步执行顺序---管中窥豹

    有一个经典例子: for (var i = 0; i < 10; i++) {setTimeout(function() { console.log(i); }, 100 * i); } 介绍一 ...

  3. js的事件循环机制,同步和异步,以及宏任务与微任务的执行顺序

    前置知识点(重要): 1.什么是事件循环:js是单线程语言,同个时间执行一件事(同步),但是他可以有一个异步队列,遇到异步操作(比如说ajax这种阻塞时间很久的事情)把它们先放入异步队列,并且继续往下 ...

  4. js回调执行顺序,同步任务与异步任务,宏任务与微任务

    JS执行顺序 JS是单线程的,即一段时间只能执行一个任务.执行一段代码,js总是按照顺序执行的,只不过在执行的过程中不会等待异步任务. 同步任务与异步任务 同步任务:立即执行的任务,直接被主线程读取并 ...

  5. php 内部异步执行顺序,event_loop中不同异步操作的执行顺序

    关于js的单线程.怎么创建一个异步任务都是老生常谈的话题了,我们今天就总结一下js不同的异步操作到底执行顺序如何. 首先我们要明白js两种任务类型,一个是macrotask(宏任务),一个是 micr ...

  6. Ajax同步异步执行顺序问题

    今天项目中碰到一个问题,大概是这样的:JS中一个方法A需要先给隐藏域赋值,然后另一个方法B再从这个隐藏域取值,获取到这个值后给接口传参然后请求数据.也就是说这两个方法需要有执行顺序,A方法先执行,然后 ...

  7. C# async/awit 嵌套异步 执行顺序 分析

    使用非异步方法调用可异步方法(内含嵌套异步) 效果图: 代码(在控制台mian函数中运行该函数): private static void AsyncTest(){Func<Task<st ...

  8. react学习(50)--解决异步执行顺序问题

    this.props.dispatch({type: 'activity/addActivityPopup',payload: params,callback: (res) => {if (re ...

  9. 【微前端开发环境下,加载远程子应用的实战。】

    一开始我们的本地开发运行的环境,如果没有启动子应用的话.对应的页面是白屏的. 问题: 当有关联资源需要跳转时无法跳转,需要额外打开一个浏览器tab页到环境上面执行操作. 当bug类型为纯ui-serv ...

最新文章

  1. python爬虫框架实例项目_python爬虫框架scrapy实例详解
  2. 几款开源的数据挖掘工具
  3. 企业网络带宽需求和跨地域网络连接的优化
  4. sqli-lab(16)
  5. 西南交大计算机机试题,西南交大 土木茅以升班 计算机应用基础试题(2004年) B卷...
  6. foreach 和 for 循环的区别
  7. 2.9 什么是端到端的深度学习
  8. android videoview截屏,android VideoView截屏黑屏解决方法
  9. 运动控制器PSO位置同步输出(一):硬件平台与PSO指令简介
  10. 【基础整理】Mapping representation 机器人所用地图种类及相关介绍
  11. 幂函数导数公式的推导
  12. 成功启动electron-egg项目,electron+vue的傻瓜式搭建
  13. arm搭建云手机教程_全球首个ARM云手机解决方案 基于ARM架构华为云云手机开启公测...
  14. 命令控制qq自动申请远程控制_代码详解
  15. vue ui创建项目 连接断开(errno:-4058,syscall: ‘scandir‘,code:’ ENOENT’,path: ‘C: ....../locales)
  16. 樱桃牌-高逼格键盘敲代码贼爽!包邮送你!
  17. C#GPS坐标转百度地图坐标
  18. uniapp-自定义下拉菜单,点击选项绑定数据
  19. 刻意练习:如何从新手到大师
  20. 计算机用户日记怎么查询系统,如何查看电脑使用记录,简单几步就能看到

热门文章

  1. oracle connectionstring 属性尚未初始化.,ConnectionString属性尚未初始化的解决方法
  2. SqlServer数据库删除数据
  3. linux安装usermod命令,usermod命令
  4. VCamSDK 4.1 qt 使用 (sip 客户端打开分享桌面测试)
  5. linux刷windows phone,使用WoA-Installer工具在Lumia 950/XL上安装Windows 10 ARM
  6. vue iview Menu改造为五边形菜单
  7. 哈夫曼树与带权路径长度
  8. 面试官是小我3岁的未来领导,瞬间不想去!
  9. Emmet 插件使用教程
  10. android post请求时报415错误,解决微信小程序用 SpringMVC 处理http post时请求报415错误...