- 宏任务
(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
JS分为同步任务和异步任务,同步任务都在主线程上执行,形成一个执行栈
- 微任务
microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
运行机制
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
- 执行一个宏任务(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
- 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
自我理解如下:
- 执行调用栈中的全局Script同步代码,这些同步代码有一些是同步语句,有一些是异步语句(比如setTimeout等);
- 全局Script代码执行完毕后,调用栈Stack会清空;
- 执行微队列microtask queue中所有任务,执行微任务A的过程中若又遇到微任务B,那么先按顺序执行同步事件,再执行微任务B中的异步事件,最后执行微任务A的异步事件
- 执行宏队列macrotask queue中的任务
宏任务包含:
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)
举例
let foo = () => {
console.log(111)
setTimeout(()=>{
console.log(333)
new Promise((resolve1, reject1) =>{
new Promise((resolve2,reject2) => {
console.log(444)
resolve2();
}).then(()=>{
console.log(666)
})
console.log(555)
resolve1(777);
}).then(resolve => console.log(resolve))
}, 0)
new Promise((resolve, reject) =>
resolve(222)
).then(resolve => console.log(resolve))
}
foo();
ES6和ES7的不同写法
//ES7里
async function async1() {
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2 end')
}
async1()
//ES6里
new Promise((resolve, reject) => {
// console.log('async2 end')
async2()
...
}).then(() => {
// 执行async1()函数await之后的语句
console.log('async1 end')
})
new Promise((resolve, reject) => {
setTimeout(() => resolve(new Promise(res => res(333))), 2000)
}).then(res => {
console.log(res)
return 222
}).then().then(res => {
console.log(res);
return new Promise(res => {
setTimeout(() => { res(666) }, 1000)
}).then(res => {
console.log(res);
return 999
})
}).then(res => {
console.log(res);
})
//结果
333
222
666
999
如果在promise里面再写一个promsie的话,由于里面的promise的then要比外面的promise的then先执行,也就是说它的nextTick更先注册,如下代码
new Promise((resolve, reject) => {
setTimeout(() => resolve(new Promise(res => res(111))), 2000)
}).then(res => {
console.log(res);
new Promise((resolve,reject) => {
resolve( 222)
}).then(res => {
console.log(res);
})
return 333
}).then(res => {
console.log(res);
})
代码若更换成如下,在内嵌的promise里加上setTimeout,输出结果就会改变
new Promise((resolve, reject) => {
setTimeout(() => resolve(new Promise(res => res(111))), 2000)
}).then(res => {
console.log(res);
new Promise(res => {
setTimeout(() => { res(333) }, 1000)
}).then(res => {
console.log(res);
})
return 222
}).then(res => {
console.log(res);
})
网友评论