宏任务和微任务
Posted Anastasia..
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了宏任务和微任务相关的知识,希望对你有一定的参考价值。
目录
javascript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
为了协调事件、用户交互、脚本、UI 渲染和网络处理等行为,防止主线程的不阻塞,Event Loop 的方案应用而生。Event Loop 包含两类:一类是基于 Browsing Context,一种是基于 Worker。
二者的运行是独立的,也就是说,每一个 JavaScript 运行的"线程环境"都有一个独立的 Event Loop,每一个 Web Worker 也有一个独立的 Event Loop。
一、宏任务和微任务
先做题:
setTimeout(function()
console.log('setTimeout')
,0)
//同步
console.log('script start')
async function async1()
//同步
console.log('async1 start');
await async2()
//异步
console.log('async1 end')
async function async2()
//同步
console.log('async2 end')
//微任务
new Promise(function(resolve)
//同步
console.log('promise')
for (var i = 0; i <10000; i++)
if (i === 10)
console.log("3")
i == 9999 && resolve('4')
resolve();
).then(function(val)
console.log(val)
//异步
console.log('promise1')
).then(function(res)
console.log(res)
console.log('promise2')
)
//微任务
async1();
//同步
console.log('script end')
宏任务:
setTimeout setInterval Ajax DOM事件 script(整体代码) I/OUI交互事件 postMessageMessage Channel setImmediate(Node.js 环境)
微任务:
Promise async/await Object.observe MutationObserver process.nextTick(Node.js 环境)
微任务比宏任务的执行时间要早
异步和单线程
异步和单线程是相辅相成的,js是一门单线程脚本语言,所以需要异步来辅助
异步和同步的区别:
异步不会阻塞程序的执行,
同步会阻塞程序的执行,
前端使用异步的场景:
定时任务:
setTimeout,setInverval
网络请求:
ajax请求,动态<img>加载
事件绑定
任务队列和event loop(事件循环)
1)所有的同步任务都在主线程上执行,行成一个执行栈。
2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。
3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。
4)重复上面三步。
只要主线程空了,就会读取任务列队,这就是js的运行机制,也被称为 event loop(事件循环)。
考察的是事件循环和回调队列。注意以下几点:
Promise 优先于 setTimeout 宏任务,所以 setTimeout 回调会最后执行
Promise 一旦被定义就会立即执行
Promise 的 resolve 和 reject 是异步执行的回调。所以 resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 之前调用
await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象
解析:
首先,事件循环从宏任务(macrostack)队列开始,这个时候,宏任务队列中,只有一个 script (整体代码)任务。从宏任务队列中取出一个任务来执行。
首先执行 console.log('script start'),输出 ‘script start'
遇到 setTimeout 把 console.log('setTimeout') 放到 macrotask 队列中
执行 aync1() 输出 ‘async1 start' 和 'async2' ,把 console.log('async1 end') 放到 micro 队列中
执行到 promise ,输出 'promise1' ,把 console.log('promise2') 放到 micro 队列中
执行 console.log('script end'),输出 ‘script end'
macrotask 执行完成会执行 microtask ,把 microtask quene 里面的 microtask 全部拿出来一次性执行完,所以会输出 'async1 end' 和 ‘promise2'
开始新一轮的事件循环,去除执行一个 macrotask 执行,所以会输出 ‘setTimeout'
js 宏任务和微任务
1.概念:宏任务(macrotask )和微任务(microtask ) 表示异步任务的两种分类。常见宏任务:I/O 、setTimeout、setInterval;微任务:Promise.then catch finally、process.nextTick
在挂起任务时,JS 引擎会将 所有任务 按照类别分到这两个队列中,
首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;
之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
2.代码
2.1 基本执行顺序
// 主线程(外层宏) - 微 - 宏 // 1 1.1 - 2 - 3 setTimeout(() => console.log(‘3‘) , 0) console.log(‘1‘); new Promise((resolve) => console.log(‘1.1‘); resolve() ).then(() => console.log(‘2‘); ).then(()=> console.log(‘2.1‘) )
setTimeout(_ => console.log(4)) new Promise(resolve => resolve() console.log(1) ).then(_ => console.log(3) ) console.log(2)
2.2 深度解析案例 :单组依次执行
console.log(‘1‘); setTimeout(function() console.log(‘3‘); new Promise(function(resolve) console.log(‘3.1‘); resolve(); ).then(function() console.log(‘4‘) ) ) new Promise(function(resolve) console.log(‘1.1‘); resolve(); ).then(function() console.log(‘2‘) ) setTimeout(function() console.log(‘5‘); new Promise(function(resolve) console.log(‘5.1‘); resolve(); ).then(function() console.log(‘6‘) ) )
2.3 promise ES5实现
function MyPromise(fn) var value = null, callbacks = []; this.then = function (onFulfilled) callbacks.push(onFulfilled); return this; ; function resolve(value) setTimeout(function () callbacks.forEach(function (callback) callback(value); ); ,0) fn(resolve); function test() return new MyPromise(function(resolve) console.log(‘1‘); resolve(); ) test().then(function(resolve) console.log(‘2‘); ).then(function(resolve) console.log(‘3‘); );
3.相关文章
以上是关于宏任务和微任务的主要内容,如果未能解决你的问题,请参考以下文章