以下理解整合非原创,侵删
宏任务
宏任务包含:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)
运行机制(事件循环)
在单次循环中,一次最多处理一个macrotask(其他的仍然驻留在队列中),然而却可以处理完所有的microtask。
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
事件循环执行顺序
以下来自:https://www.cnblogs.com/shiyunfront/p/13095128.html
//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
//微事件1
process.nextTick(function() {
console.log('6');
})
//主线程直接执行
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
//微事件2
console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
首先浏览器执行js进入第一个宏任务进入主线程, 直接打印console.log('1')
• 遇到 setTimeout 分发到宏任务Event Queue中
• 遇到 process.nextTick 丢到微任务Event Queue中
• 遇到 Promise, new Promise 直接执行 输出 console.log('7');
• 执行then 被分发到微任务Event Queue中
•第一轮宏任务执行结束,开始执行微任务 打印 6,8
•第一轮微任务执行完毕,执行第二轮宏事件,执行setTimeout
•先执行主线程宏任务,在执行微任务,打印'2,4,3,5'
•在执行第二个setTimeout,同理打印 ‘9,11,10,12’
•整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014
练习(注释为自我理解)
function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
//1.
console.log("test start...");
const v1 = await testSometing();//关键点1
//第一个被扔进第一轮事件循环的微任务队列
//v1="testSometing"
console.log(v1);
const v2 = await testAsync();
//v2="hello async"
console.log(v2);
console.log(v1, v2);
}
new Promise(((resolve, reject) => {
console.log("test start...");
}))
test();
var promise = new Promise((resolve)=> {
console.log("promise start..");
resolve("promise");
});//关键点2
//第二个被扔进第一轮事件循环的微任务队列
promise.then((val)=> console.log(val));
console.log("test end...")
//第一轮事件循环开始
// 同步任务
// console.log("test start...");
// console.log("执行testSometing");
// console.log("promise start..");
// console.log("test end...")
// 开始执行微任务队列
// console.log(v1); // //v1="testSometing"
//console.log(val) val="promise"
//第二轮循环
// console.log("执行testAsync");
//第三轮
// console.log(v2);"hello async"
// console.log(v1, v2);
async function async1() {
console.log('2')
await async2()
console.log('7')
}
async function async2() {
console.log('3')
}
setTimeout(function () {
console.log('8')
}, 0)
console.log('1')
async1()
new Promise(function (resolve) {
console.log('4')
resolve()
}).then(function () {
console.log('6')
})
console.log('5')
//第一轮事件循环
//同步
//12345
//微任务
//76
//第二轮
//8