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. JAVA_SE基础——35.static修饰成员函数

    在Java中适用static关键字修饰的方法称为静态方法. 声明静态方法的语法格式如下: 权限修饰符 static 数据类型 方法名(){ 方法体 } 静态方法 可以使用类名直接调用     类名.方 ...

  2. 我自己总结的C#开发命名规范整理了一份

    我自己总结的C#开发命名规范整理了一份 标签: 开发规范文档标准语言 2014-06-27 22:58 3165人阅读 评论(1) 收藏 举报  分类: C#(39)  版权声明:本文为博主原创文章, ...

  3. bootstrap 菜单之手风琴效果

    自己用bootstrap搭了个项目,纯属娱乐....为了检验学习bootstrap之成果. 效果如图: 一.搭建中发现一问题,因为以前测试都是写的html页面,这次用了母版页,点击页面的之后,页面会刷 ...

  4. JavaScript中的单体模式四种实现方式

    /* 1 简单单体 */ var Singleton = { attr1: 1 , method1:function(){ //do sth } }; alert(Singleton.attr1); ...

  5. 1.4 正则化 regularization

    如果你怀疑神经网络过度拟合的数据,即存在高方差的问题,那么最先想到的方法可能是正则化,另一个解决高方差的方法就是准备更多数据,但是你可能无法时时准备足够多的训练数据,或者获取更多数据的代价很高.但正则 ...

  6. CBC翻转攻击(实验吧_简单的登陆题)

    题目链接 http://ctf5.shiyanbar.com/web/jiandan/index.php 有源码在test.php页面 分析代码过程 如果post id,将id转字符串,然后进入sql ...

  7. 分析ajax请求抓取今日头条关键字美图

    # 目标:抓取今日头条关键字美图 # 思路: # 一.分析目标站点 # 二.构造ajax请求,用requests请求到索引页的内容,正则+BeautifulSoup得到索引url # 三.对索引url ...

  8. [Nginx]-外部多端口映射Https443端口配置

    https服务器配置完成后,域名访问默认匹配至443端口,如果想同时通过https域名网址来请求多个对外服务,就需要在Nginx配置里来对请求进行规则判断,并匹配至相应的内部端口,这也是Nginx反向 ...

  9. [LeetCode] Top K Frequent Words 前K个高频词

    Given a non-empty list of words, return the k most frequent elements. Your answer should be sorted b ...

  10. [LeetCode] Dota2 Senate 刀塔二参议院

    In the world of Dota2, there are two parties: the Radiant and the Dire. The Dota2 senate consists of ...