小满视频
参考文章:
JS执行机制详解
这一次,彻底弄懂 JavaScript 执行机制
- 宏任务中的同步任务:script、new promise 立即执行
- 宏任务(macro-task):setTimeOut、setInterval
- 微任务(mincro-task):promise.then、process.nextTick(node)
setTimeOut:设置的时间意思是在多久后将此宏任务放到队列中,而不是在队列中等待时间到了才执行
await:微任务,在await之后执行的代码,必须等到await执行完毕后才可以执行,
执行流程
- 自上而下分析script中代码
- 同步任务依次加入主线程准备执行
- 宏任务放到宏任务队列中,微任务放到微任务队列
- 主线程中的代码执行,执行中出现的宏任务和微任务继续添加到队列中
- 微任务队列中任务放到主线程执行
- 微任务执行完毕(此时完成一个循环,开启下一个循环)
- 再把宏任务队列中任务放到主线程中执行,执行中出现的宏任务和微任务继续添加到队列中,重复步骤:4–7
示例代码
async function Prom() {
console.log("1");
await Promise.resolve();
console.log("2");// 写在await Promise后面相当于then,加入微任务
}
setTimeout(() => {
console.log("3");
Promise.resolve().then(() => {
console.log(`4`);
})
},0);
Promise.resolve().then(() => {
console.log("5");
})
Prom();
console.log(0);
执行顺序
1. 自上而下分析script代码,进入主线程执行的是:
Prom();
console.log(0);
- 进入宏任务队列的代码:
setTimeout(() => {
console.log("3");
Promise.resolve().then(() => {
console.log(`4`);
})
},0);// 设置等待时间为0,立即会被放到宏任务队列中
- 进入微任务队列的代码:
Promise.resolve().then(() => {
console.log("5");
})
- script中的代码都进入了相对应的队列,现在主线程开始执行
- 执行
Prom();
这个方法调用的Prom
方法,代码是:
async function Prom() {
console.log("1");
await Promise.resolve();
console.log("2");
}
- 执行
console.log("Y");
—控制器输出:1 - 执行下一句:
await Promise.resolve();
发现这是一个微任务,加入到微任务的队列中,现在微任务的队列中有两个任务:
// 微任务队列中的任务,1
Promise.resolve().then(() => {
console.log("5");
})
// 微任务队列中的任务,2
await Promise.resolve();
console.log("2");// 写在await Promise后面相当于then,加入微任务
-
主线程中还剩一个任务:
console.log(0);
,执行,控制器输出:1 0 -
此时主线程中的任务已经全部完成,接下来执行微任务队列
-
微任务中的任务放到主线程执行,微任务1:
Promise.resolve().then(() => { console.log("5"); })
控制器输出:1 0 5 -
微任务2:
await Promise.resolve();console.log("2");
控制器输出:1 0 5 2 -
此时微任务队列也被清空
-
此时一个循环周期的任务完成,准备执行下一个循环
-
宏任务队列的代码放入主线程执行
-
宏任务执行
setTimeout()
方法,console.log("3");
控制器输出:1 0 5 2 3 -
seiTimeout()
方法中执行到Promise.resolve().then(() => { console.log(
4); })
将此任务放入到微任务队列中,继续执行宏任务队列,宏任务队列此时已经没有任务。 -
执行微任务代码
Promise.resolve().then(() => { console.log(
4); })
,控制器输出:1 0 5 2 3 4 -
执行完毕,共用了两个执行周期
nextTick
- 在组件中数据是同步的,Dom是异步的,当数据发生变化,Dom没有发生相应的变化,需要使用nextTick
有两种方法更新Dom
第一种
nextTick(()=>{
// Todo:改变Dom的操作
})
第二种
- 使用await,await后面的代码就是异步的微任务
async()=>{
}
await nexttick()
// Todo:改变Dom的操作
nextTick源代码
export function nextTick<T = void, R = void>(
this: T,
fn?: (this: T) => R,
): Promise<Awaited<R>> {
const p = currentFlushPromise || resolvedPromise
return fn ? p.then(this ? fn.bind(this) : fn) : p
}
- 为什么加上nextTick就可以刷新Dom?
源码分析可知,使用nextTick
后,代码会放入到Promise.resolve().then(()=>{// 代码放在这里执行})
,添加到微任务队列中执行