异步 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 ...
随机推荐
- 让linux远程主机在后台运行脚本
后台挂起:python xxx.py & 在脚本命令后面加入"&"符号就可以后台运行.结束进程:kill -9 sidps -ef | grep ... 查询sid
- C语言Linix服务器网络爬虫项目(一)项目初衷和网络爬虫概述
一.项目初衷和爬虫概述 1.项目初衷 本人的大学毕设就是linux上用c写的一个爬虫,现在我想把它完善起来,让他像一个企业级别的项目.为了重复发明轮子来学习轮子的原理,我们不使用第三方框架(这里是说的 ...
- eclipse maven项目目录
今天遇见一个错误,关于eclipse项目的路径问题,web-inf的路径,上图和下图出现了两种web-INF,src的web-INFf和webContent的web-INF,src里面的文件需要编译以 ...
- 记一次向maven中央仓库提交依赖包
Maven是Java中最常用的依赖管理工具,Maven的中央仓库保罗万象,涵盖了各个领域的框架.工具和文档,也是Java生态强大生命力的体现.我们自己开发的一些有用有趣的代码也可以通过打包上传到mav ...
- LeetCode & Q13-Roman to Integer-Easy
Math String Description: Given a roman numeral, convert it to an integer. Input is guaranteed to be ...
- CentOS 7 Redis安装配置
1.获取Redis压缩包: wget http:.tar.gz 2.解压测试: mv 到 /usr/local/ tar .tar cd redis 3.使用make测试编译: make 这里可能会出 ...
- 裸辞两个月,海投一个月,从Android转战Web前端的求职之路
前言 看到这个标题的童鞋,可能会产生两种想法: 想法一:这篇文章是标题党 想法二:Android开发越来越不景气了吗?前端越来越火了吗? 我一向不喜欢标题党,标题中的内容是我的亲身经历.我是2016年 ...
- Hey,man,are you ok? -- 关于心跳、故障监测、lease机制
电话之于短信.微信的一个很大的不同点在于,前者更加及时,有更快速直接的反馈:而后面两个虽然称之为instant message,但经常时发出去了就得等对方回复,等多久是不确定的.打电话能明确知道对方在 ...
- 算法题丨3Sum Closest
描述 Given an array S of n integers, find three integers in S such that the sum is closest to a given ...
- Python内置函数(2)——divmod
英文文档: divmod(a, b) Take two (non complex) numbers as arguments and return a pair of numbers consisti ...