js中的宏任务与微任务
如果你已经知道了js中存在宏任务和微任务,那么你一定已经了解过promise了。因为在js中promise是微任务的一个入口。
先来看一道题:
setTimeout(function(){
console.log('setTimeout')
});
new Promise(function(resolve, reject){
console.log('pormise body');
resolve();
}).then(function(){
console.log('promise then')
});
console.log('main');
这题的答案是:
promise body
main
promise then
setTimeout
promise body出现在第一行一点也不意外,意外的是,setTimeout出现在了promise then的后边。
setTimeout和promise then都是异步调用,setTimeout又定义在promise之前,如果没有意外,应该是先输出setTimeout才对,但这里却恰恰相反。
这里涉及到的知识点,就是宏任务与微任务了。标记一下上边的代码:
setTimeout(function(){ // 同步代码,语句1
console.log('setTimeout') // 宏任务,语句2
});
new Promise(function(resolve, reject){
console.log('pormise body'); // 同步代码,语句3
resolve(); // 同步代码,语句4
}).then(function(){
console.log('promise then') // 微任务,语句5
});
console.log('main'); // 同步代码,语句6
那么他们运行的规则是怎样的呢?
原来,宏任务与微任务,都各自有一个调用队列(先进先出)。
遇到宏任务,微任务,则将他们推入各自的调用队列。需要注意的是,同步代码也是宏任务。
宏任务执行完一个,则去清空微任务队列,微任务清空后再去执行下一个宏任务。
这个过程颇像去医院诊室排队看大夫的情景:
如果有一个病人A叫到号以后,又被大夫安排先去做检查,那么做完检查以后病人A回到诊室门口,可以直接等待当前正在看病的病人B与大夫交谈结束后,将检查结果交给大夫,而不用再次排队。
我们来把上面的代码一行一行解读一下:
首先定义两个队列,宏任务队列:MacroQqueue, 微任务队列: MicroQueue
第一步,先按同步代码顺序运行
同步代码,语句1: 添加一个宏任务,将语句2推入MacroQueue。 // MacroQueue: [{task: 语句2}]
同步代码,语句3: 打印promise body
同步代码,语句4: 添加一个微任务,将语句5推入MicroQueue。 // MicroQueue: [{task: 语句5}]
同步代码,语句6: 打印main。 // 同步代码(宏任务)完成
第二步,开始清空微任务队列
微任务: 语句5,从MicroQueue跳出,打印promise then。 // 微任务队列全部清空
第三步,开始清空宏任务队列
宏任务:语句2,从MacroQqueue跳出,打印setTimeout // 宏任务队列全部清空
第四步:开始清空微任务队列
队列为空...
一轮循环完成。开始下一轮,如此循环下去。
通过上面的讲解,大家应该能对宏任务,微任务的运行机制有了一定的了解了吧。那么都有哪些常见的宏任务与微任务呢?
请看下表:
| 宏任务 | 浏览器 | nodejs |
|---|---|---|
| 同步代码 | ✅ | ✅ |
| I/O | ✅ | ✅ |
| setTimeout | ✅ | ✅ |
| setInterval | ✅ | ✅ |
| setImmediate | ❌ | ✅ |
| requestAnimationFrame | ✅ | ❌ |
| 微任务 | 浏览器 | nodejs |
|---|---|---|
| process.nextTick | ❌ | ✅ |
| MutationObserver | ✅ | ❌ |
| Promise (async/await) | ✅ | ✅ |
好了,我们来一道复杂一点的题练练手:
console.log('sync statement 1');
Promise.resolve().then(function() {
console.log('micro task 1');
setTimeout(function() {
console.log('macro task 1');
}, 0);
}).then(function() {
console.log('micro task 2');
});
setTimeout(function() {
console.log('macro task 2')
Promise.resolve().then(function(){
console.log('micro task 3');
})
}, 0)
console.log('sync statement 2');
//输出:
// sync statement 1
// sync statement 2
// micro task 1
// micro task 2
// macro task 2
// micro task 3
// macro task 1
标注一下方便大家分析:
console.log('sync statement 1'); // 同步代码,语句1
Promise.resolve().then(function() { // 同步代码,语句2,注册了一个微任务
console.log('micro task 1'); // 微任务,语句3
setTimeout(function() { // 微任务,语句4,同时注册了一个宏任务
console.log('macro task 1'); // 宏任务,语句5
}, 0);
}).then(function() {
console.log('micro task 2'); // 微任务,语句6
});
setTimeout(function() { // 同步代码,语句7
console.log('macro task 2') // 宏任务,语句8
Promise.resolve().then(function(){ // 宏任务,语句9,同时注册了一个微任务
console.log('micro task 3'); // 微任务,语句10
})
}, 0)
console.log('sync statement 2'); // 同步代码,语句11
js中的宏任务与微任务的更多相关文章
- javascript中的宏任务和微任务(一)
一.宏任务和微任务有哪些 宏任务:setTimeout,setInterval,ajax,dom,宏任务是由浏览器提供的 微任务:promise,async/await,微任务是由es6提供的 二.微 ...
- javascript中的宏任务和微任务(二)
js事件轮询执行顺序总结: 1)所有的同步任务都在主线程上执行,行成一个执行栈. 2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记. 3)主线程完成所有 ...
- JS异步之宏队列与微队列
1. 原理图 2. 说明 JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队 宏列队:用来保存待执行的宏任务(回调),比如:定时器回调.DOM 事件回调.ajax 回调 微列队:用来保存待 ...
- JS中EventLoop、宏任务与微任务的个人理解
为什么要EventLoop? JS 作为浏览器脚本语言,为了避免复杂的同步问题(例如用户操作事件以及操作DOM),这就决定了被设计成单线程语言,而且也将会一直保持是单线程的.而在单线程中若是遇到了耗时 ...
- JavaScript同步模式,异步模式及宏任务,微任务队列
首先JavaScript是单线程的语言,也就是说JS执行环境中,负责执行代码的线程只有一个.一次只能执行一个任务,如果有多个任务的话, 就要排队,然后依次执行,优点就是更安全,更简单.缺点就是遇到耗时 ...
- JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)
1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...
- js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)
javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...
- js 宏任务和微任务
.宏任务(macrotask )和微任务(microtask ) macrotask 和 microtask 表示异步任务的两种分类. 在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首 ...
- js 同步 异步 宏任务 微任务 文章分享
分享一篇 写的很好的 宏任务 微任务 同步异步的文章 文章原地址: https://juejin.im/post/59e85eebf265da430d571f89 这一次,彻底弄懂 JavaScri ...
随机推荐
- python 3.7.5 官方tutorial 学习笔记
用了好久python,还没有完整看过官方的tutorial,这几天抽空看了下,还是学到些东西 --- Table of Contents 1. 课前甜点 2. 使用 Python 解释器 2.1. 调 ...
- 深度解密Go语言之 pprof
目录 什么是 pprof pprof 的作用 pprof 如何使用 runtime/pprof net/http/pprof pprof 进阶 Russ Cox 实战 查找内存泄露 总结 参考资料 相 ...
- 星空:差分,状压dp
总算不再是能用暴力卡常/随机化水过的好T3了. 说是打了两个标签,实际上最关键的是题意转化. 如果你丝毫不转化的话也可以: #include<bits/stdc++.h> using na ...
- C/C.cpp
我是怎么说服自己这题没有答案单调性的? 当轮数大于最优答案时,B的操作就成了捣乱,会使A多进行若干操作才能回复原状态 嗯,所以答案没有单调性. 就没去想A的操作可以把B的抵消啊.. 另外swap没有交 ...
- NOIP模拟测试8反思
被动态逆序对戏耍,来写博客这次考试油炸了 模板爆零,哈希调半天导致T3没时间,我都干了些什么&_& T3思路: 利用环的性质先拼成一条链,然后二分边界. 证明就不说啦(其实是我不会) ...
- 「Luogu 1349」广义斐波那契数列
更好的阅读体验 Portal Portal1: Luogu Description 广义的斐波那契数列是指形如\(an=p \times a_{n-1}+q \times a_{n-2}\)的数列.今 ...
- 【Spring】Spring的定时任务注解@Scheduled原来如此简单
1 简介 定时任务的实现非常多,JDK的Timer.Spring提供的轻量级的Scheduled Task.QuartZ和Linux Cron等,还有一些分布式的任务调度框架.本文主要介绍Schedu ...
- 微擎 manifest.xml
微擎 manifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns= ...
- nyoj 38-布线问题(prim, sort)
38-布线问题 内存限制:64MB 时间限制:1000ms Special Judge: No accepted:5 submit:11 题目描述: 南阳理工学院要进行用电线路改造,现在校长要求设计师 ...
- 用maven创建web项目(spring Mvc)
用maven创建web项目(spring Mvc) 1.打开cmd进入到你要创建maven项目的目录下: 2.输入以下命令.然后根据提示输入相应的groupId.artifactId.version: ...