异步执行顺序——宏任务与微任务不同环境下的出队规则
导读
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
异步执行顺序——宏任务与微任务不同环境下的出队规则相关推荐
- 一篇文章理解JS中同步任务和异步任务以及宏任务与微任务的原理和执行机制
前言: javascript是一种单线程编程语言, 一般来说它的执行顺序是按照从上到下执行,但是有些特殊情况则会改变这样的执行顺序,我们需要理解和掌握其中的原理,需要了解同步任务和异步任务以及宏任务和 ...
- javascript的异步执行顺序---管中窥豹
有一个经典例子: for (var i = 0; i < 10; i++) {setTimeout(function() { console.log(i); }, 100 * i); } 介绍一 ...
- js的事件循环机制,同步和异步,以及宏任务与微任务的执行顺序
前置知识点(重要): 1.什么是事件循环:js是单线程语言,同个时间执行一件事(同步),但是他可以有一个异步队列,遇到异步操作(比如说ajax这种阻塞时间很久的事情)把它们先放入异步队列,并且继续往下 ...
- js回调执行顺序,同步任务与异步任务,宏任务与微任务
JS执行顺序 JS是单线程的,即一段时间只能执行一个任务.执行一段代码,js总是按照顺序执行的,只不过在执行的过程中不会等待异步任务. 同步任务与异步任务 同步任务:立即执行的任务,直接被主线程读取并 ...
- php 内部异步执行顺序,event_loop中不同异步操作的执行顺序
关于js的单线程.怎么创建一个异步任务都是老生常谈的话题了,我们今天就总结一下js不同的异步操作到底执行顺序如何. 首先我们要明白js两种任务类型,一个是macrotask(宏任务),一个是 micr ...
- Ajax同步异步执行顺序问题
今天项目中碰到一个问题,大概是这样的:JS中一个方法A需要先给隐藏域赋值,然后另一个方法B再从这个隐藏域取值,获取到这个值后给接口传参然后请求数据.也就是说这两个方法需要有执行顺序,A方法先执行,然后 ...
- C# async/awit 嵌套异步 执行顺序 分析
使用非异步方法调用可异步方法(内含嵌套异步) 效果图: 代码(在控制台mian函数中运行该函数): private static void AsyncTest(){Func<Task<st ...
- react学习(50)--解决异步执行顺序问题
this.props.dispatch({type: 'activity/addActivityPopup',payload: params,callback: (res) => {if (re ...
- 【微前端开发环境下,加载远程子应用的实战。】
一开始我们的本地开发运行的环境,如果没有启动子应用的话.对应的页面是白屏的. 问题: 当有关联资源需要跳转时无法跳转,需要额外打开一个浏览器tab页到环境上面执行操作. 当bug类型为纯ui-serv ...
最新文章
- python爬虫框架实例项目_python爬虫框架scrapy实例详解
- 几款开源的数据挖掘工具
- 企业网络带宽需求和跨地域网络连接的优化
- sqli-lab(16)
- 西南交大计算机机试题,西南交大 土木茅以升班 计算机应用基础试题(2004年) B卷...
- foreach 和 for 循环的区别
- 2.9 什么是端到端的深度学习
- android videoview截屏,android VideoView截屏黑屏解决方法
- 运动控制器PSO位置同步输出(一):硬件平台与PSO指令简介
- 【基础整理】Mapping representation 机器人所用地图种类及相关介绍
- 幂函数导数公式的推导
- 成功启动electron-egg项目,electron+vue的傻瓜式搭建
- arm搭建云手机教程_全球首个ARM云手机解决方案 基于ARM架构华为云云手机开启公测...
- 命令控制qq自动申请远程控制_代码详解
- vue ui创建项目 连接断开(errno:-4058,syscall: ‘scandir‘,code:’ ENOENT’,path: ‘C: ....../locales)
- 樱桃牌-高逼格键盘敲代码贼爽!包邮送你!
- C#GPS坐标转百度地图坐标
- uniapp-自定义下拉菜单,点击选项绑定数据
- 刻意练习:如何从新手到大师
- 计算机用户日记怎么查询系统,如何查看电脑使用记录,简单几步就能看到
热门文章
- oracle connectionstring 属性尚未初始化.,ConnectionString属性尚未初始化的解决方法
- SqlServer数据库删除数据
- linux安装usermod命令,usermod命令
- VCamSDK 4.1 qt 使用 (sip 客户端打开分享桌面测试)
- linux刷windows phone,使用WoA-Installer工具在Lumia 950/XL上安装Windows 10 ARM
- vue iview Menu改造为五边形菜单
- 哈夫曼树与带权路径长度
- 面试官是小我3岁的未来领导,瞬间不想去!
- Emmet 插件使用教程
- android post请求时报415错误,解决微信小程序用 SpringMVC 处理http post时请求报415错误...