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的更多相关文章

  1. queueMicrotask & EventLoop & macrotask & microtask

    queueMicrotask https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicro ...

  2. 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 ...

  3. 异步 JavaScript 之理解 macrotask 和 microtask(转)

    这个知识点... https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/? ...

  4. 聊聊JavaScript异步中的macrotask和microtask

    前言 首先来看一个JavaScript的代码片段: console.log(1); setTimeout(() => { console.log(2); Promise.resolve().th ...

  5. Javascript中的Microtask和Macrotask——从一道很少有人能答对的题目说起

    首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容? async function async1() { console.log('async1 start'); aw ...

  6. javascript macrotask & microtask

    先看一个 实例 案例 console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); Pr ...

  7. 异步 JavaScript - 事件循环

    简评:如果你对 JavaScript 异步的原理感兴趣,这里有一篇不错的介绍. JavaScript 同步代码是如果工作的 在介绍 JavaScript 异步执行之前先来了解一下, JavaScrip ...

  8. 【JavaScript】AJAX总结(异步JavaScript和XML)

    AJAX介绍 通过 AJAX,你可以创建更好.更快以及更友好的 WEB 应用程序. AJAX 基于 JavaScript 和 JavaScript的XMLHttpRequest对象. AJAX 应用程 ...

  9. 什么是AJAX? AJAX:”Asynchronous JavaScript and XML”中文意思:异步JavaScript和XML。

    指一种创建交互式网页应用的网页开发技术. AJAX并非缩写词,而是由Jesse James Gaiiett创造的名词. 不是指一种单一的技术,而是有机地利用了一系列相关的技术: web标准( Stan ...

随机推荐

  1. (转载) ASP.NET(C#) Web Api 通过文件流下载文件到本地实例

    下载文件到本地是很多项目开发中需要实现的一个很简单的功能.说简单,是从具体的代码实现上来说的,.NET的文件下载方式有很多种,本示例给大家介绍的是ASP.NET Web Api方式返回HttpResp ...

  2. Python-字典、集合、字符编码、文件操作整理-Day3

    1.字典 1.1.为什么有字典: 有个需求,存所有人的信息 这时候列表就不能轻易的表示完全names = ['stone','liang'] 1.2.元组: 定义符号()t = (1,2,3)tupl ...

  3. SpringCloud的DataRest(一)

    一.概念与定义 Spring Data Rest 基于Spring Data的repository,可以把 repository 自动输出为REST资源, 这样做的好处: 可以免去大量的 contro ...

  4. redis入门(05)redis的key命令

    一.什么是redis键命令 Redis 键(key):Redis 键命令用于管理 redis 的键. Redis 键命令的基本语法: redis 127.0.0.1:6379> COMMAND ...

  5. hadoop2.6.0实践:A03 例子验证

    [hadoop@LexiaofeiN1 ~]$ hdfs dfs -ls /output/grep[hadoop@LexiaofeiN1 ~]$ hdfs dfs -rm -R /output/gre ...

  6. 分布式服务框架HSF

    最近在读阿里巴巴中台战略思想与架构这本书,so和大家分享一些我get到的东东. HSF是阿里巴巴内部的分布式服务框架,这个大家都很熟悉了,先上一张HSF的工作原理图: 这个图说明了HSF框架中每个组件 ...

  7. System Rules 更好的测试

    1:编写测试事例时候,我们要从控制台拿到数据与断言进行对比,通常要编写jdk 标准输出的屏蔽控制器.文章标题的包,能够更好的为我们进行工作. package demo2; import static ...

  8. POJ1015 && UVA - 323 ~Jury Compromise(dp路径)

    In Frobnia, a far-away country, the verdicts in court trials are determined by a jury consisting of ...

  9. Python入门之Python在Win10环境下的配置(图文教程)

    请在Python官网下载Python2.7和Python3.6安装包,虽然最新的是3.6版本,但是建议两个包都安装,方便后期在IDE工具切换. Python官网:https://www.python. ...

  10. 【Web安全】DoS及其家族

    不久前我分享过的Web安全概述获得了大家的广泛关注,说明大家对Web安全这一块还是很关心的,因此木可大大将陆续推出目前常见的Web攻击手段和对应的防范策略.本期向大家介绍的是DoS和它的家族. DoS ...