异步 JavaScript 之 macrotask、microtask
1、异步任务运行机制
先运行下面的一段代码:
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
console.log('script end');
//"script start"
//"script end"
//"setTimeout"
这里一看,setTimeout的延时为 0 ,那么是不是程序执行到这里之后就立即执行setTimeout里面的函数呢?其实不是的.
这是因为 JavaScript 主线程拥有一个 执行栈 以及一个 任务队列,主线程会依次执行代码,当遇到函数时,会先将函数 入栈,函数运行完毕后再将该函数 出栈,直到所有代码执行完毕。
那么遇到 WebAPI(例如:setTimeout, AJAX)这些函数时,这些函数会立即返回一个值,从而让主线程不会在此处阻塞。而真正的异步操作会由浏览器执行,浏览器会在这些任务完成后,将事先定义的回调函数推入主线程的 任务队列 中。
而主线程则会在 清空当前执行栈后,按照先入先出的顺序读取任务队列里面的任务。
那么我们来看一下上面程序的执行顺序:
// 1. 开始执行
console.log('script start'); // 2. 打印字符串 "script start"
setTimeout(
function() { // 5. 浏览器在 0ms 之后将该函数推入任务队列
// 而到第5步时才会被主线程执行
console.log('setTimeout'); // 6. 打印字符串 "setTimeout"
},
0
); // 3. 调用 setTimeout 函数,并定义其完成后执行的回调函数
console.log('script end'); // 4. 打印字符串 "script end"
// 5. 主线程执行栈清空,开始读取 任务队列 中的任务
以上就是浏览器的异步任务的执行机制,核心点为:
- 异步任务是由浏览器执行的,不管是AJAX请求,还是setTimeout等 API,浏览器内核会在其它线程中执行这些操作,当操作完成后,将操作结果以及事先定义的回调函数放入 JavaScript 主线程的任务队列中
- JavaScript 主线程会在执行栈清空后,读取任务队列,读取到任务队列中的函数后,将该函数入栈,一直运行直到执行栈清空,再次去读取任务队列,不断循环
- 当主线程阻塞时,任务队列仍然是能够被推入任务的。这也就是为什么当页面的 JavaScript 进程阻塞时,我们触发的点击等事件,会在进程恢复后依次执行。
2、Macrotasks 和 Microtasks
Macrotask 和 microtask 都是属于上述的异步任务中的一种,我们先看一下他们分别是哪些 API :
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks: process.nextTick, Promises, Object.observe(废弃), MutationObserver
setTimeout 的 macrotask ,和 Promise 的 microtask 有什么不同呢? 我们通过下面的代码来展现他们的不同点:
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
//"script start"
//"script end"
//"promise1"
//"promise2"
//"setTimeout"
在这里,setTimeout的延时为0,而Promise.resolve()也是返回一个被resolve了promise对象,即这里的then方法中的函数也是相当于异步的立即执行任务
这里的运行结果是Promise的立即返回的异步任务会优先于setTimeout延时为0的任务执行。
原因是任务队列分为 macrotasks 和 microtasks,而Promise中的then方法的函数会被推入 microtasks 队列,而setTimeout的任务会被推入 macrotasks 队列。在每一次事件循环中,macrotask 只会提取一个执行,而 microtask 会一直提取,直到 microtasks 队列清空。
注:一般情况下,macrotask queues 我们会直接称为 task queues,只有 microtask queues 才会特别指明。
那么也就是说如果我的某个 microtask 任务又推入了一个任务进入 microtasks 队列,那么在主线程完成该任务之后,仍然会继续运行 microtasks 任务直到任务队列耗尽。
而事件循环每次只会入栈一个 macrotask ,主线程执行完该任务后又会先检查 microtasks 队列并完成里面的所有任务后再执行 macrotask
参考:清蒸不是水煮 的文章
阮一峰 - JavaScript 运行机制详解:再谈Event Loop
Philip Roberts - Help,I’m stuck in an event loop
异步 JavaScript 之 macrotask、microtask的更多相关文章
- queueMicrotask & EventLoop & macrotask & microtask
queueMicrotask https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicro ...
- How to make an HTTP request 异步 JavaScript 和 XML
https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started In order to make an HTTP request to th ...
- 异步 JavaScript 之理解 macrotask 和 microtask(转)
这个知识点... https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/? ...
- 聊聊JavaScript异步中的macrotask和microtask
前言 首先来看一个JavaScript的代码片段: console.log(1); setTimeout(() => { console.log(2); Promise.resolve().th ...
- Javascript中的Microtask和Macrotask——从一道很少有人能答对的题目说起
首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容? async function async1() { console.log('async1 start'); aw ...
- javascript macrotask & microtask
先看一个 实例 案例 console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Pr ...
- 异步 JavaScript - 事件循环
简评:如果你对 JavaScript 异步的原理感兴趣,这里有一篇不错的介绍. JavaScript 同步代码是如果工作的 在介绍 JavaScript 异步执行之前先来了解一下, JavaScrip ...
- 【JavaScript】AJAX总结(异步JavaScript和XML)
AJAX介绍 通过 AJAX,你可以创建更好.更快以及更友好的 WEB 应用程序. AJAX 基于 JavaScript 和 JavaScript的XMLHttpRequest对象. AJAX 应用程 ...
- 什么是AJAX? AJAX:”Asynchronous JavaScript and XML”中文意思:异步JavaScript和XML。
指一种创建交互式网页应用的网页开发技术. AJAX并非缩写词,而是由Jesse James Gaiiett创造的名词. 不是指一种单一的技术,而是有机地利用了一系列相关的技术: web标准( Stan ...
随机推荐
- LeetCode & Q35-Search Insert Position-Easy
Array Binary Search Description: Given a sorted array and a target value, return the index if the ta ...
- Python内置函数(49)——isinstance
英文文档: isinstance(object, classinfo) Return true if the object argument is an instance of the classin ...
- Docker学习笔记 - Docker容器的网络基础
一.虚拟网桥 docker0 docker0 是 linux的虚拟网桥,守护进程通过docker0给容器提供网络连接的各种服务. 网桥是数据链路层设备,通常ip地址是网络层的设置.linux的虚拟网桥 ...
- JAVAFX-5 开发应用
fx 属性与布局 属性与布局是一个具备gui开发能力的开发者,快速进入开发必备的知识储备,下面简单说一说常用的属性,与布局 颜色 颜色 在 javafx.scene.paint.Color 类中提供了 ...
- 记录项目中用的laypage分页代码
最终才觉得,好记性不如烂笔头,毕竟已经不是刚毕业时候的巅峰了,精力有所下降,很多时候记不住东西. 参考url:http://www.layui.com/laypage/ 直接上代码了 <scri ...
- Python入门之三元表达式\列表推导式\生成器表达式\递归匿名函数\内置函数
本章目录: 一.三元表达式.列表推导式.生成器表达式 二.递归调用和二分法 三.匿名函数 四.内置函数 ================================================ ...
- 关于jsp页面加载时报错500的问题
先说一下,问题的发生,个人做了个小系统,成品以后运行了几次,没有问题,结果最后一次测试时,发现登陆页面报错了: 账号密码输入正确,经过后台登陆后,按理说是应该进入登陆成功后的jsp页面,然而结果却是: ...
- building a new horizon
昨天是4月14日,也是我的23岁生日.正好去参加GDG举办的WTM,这次的主题是building a new horizon. 写一下印象深刻的分享者和她们的闪光点. 1.羡辙-从灵感到落地 羡辙是在 ...
- 使用WSUS离线下载补丁并安装在非联网的windows系统中(以Windows Server 2008 r2为例)
首先我失去https://serverfault.com/questions/322938/finding-and-downloading-all-available-win2008-r2-and-w ...
- sumo快速运行简单仿真实例详细教程
本文旨在让大家快速的了解sumo,并给出运行一个简单的sumo的例子的教程,进而了解基本sumo工程的架构,使大家对该软件产生兴趣并持续学习下去,刚开始学习仿真的确枯燥,项目"跑起来&quo ...