宏任务与微任务的执行顺序
同步任务和异步任务
JavaScript是单线程执行的语言,在同一个时间只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS中出现了同步任务和异步任务。
(1)同步任务
在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。
(2)异步任务
不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以者种机制被叫做事件循环(Event Loop)
执行顺序示例
1、new promise事件只要建立,里面的代码会立即执行;
2、promise.then()和process.nextTick()的代码会在本轮"事件循环"结束时执行;
3、setTimeoutd(fn, 0)的代码会在下一轮"事件循环"开始时执行;
4、最后执行setTimeout(fn,1000)的代码。
setTimeout(function () {
var np =new Promise(function (resolve,reject) {
console.log(1)
resolve()
})
np.then(_=>{
console.log(2)
})
console.log(3)
},1000)
var pro = new Promise((resolve, reject) => {
console.log(5)
resolve()
}).then(_=>{
setTimeout(function () {
console.log(6)
},0)
return 7;
}).then(n=>{
console.log(n)
})
console.log(4)
//执行结果 5 4 7 6 1 3 2
js会先执行 同步任务 例如题中的console.log()再执行new Promise中的console.log(),再寻找
异步任务中的微任务 promise.resolve.then(),最后寻找 异步任务中的宏任务 setTimeout(),最后执行结束。
// 整体script作为第一个宏任务进入主线程......0
// 同步任务console.log直接执行
console.log('1'); ......1
async function first() {
console.log('first函数'); ......3
}
// 宏任务最后执行
setTimeout(() => {
console.log('settimeout 2'); .......7
}, 0);
// .then微任务
Promise.resolve().then(() => {
console.log('promise 3'); ......5
});
// 遇到new Promise直接执行,遇到.then分配到微任务队列中
new Promise((resolve, reject) => {
// new Promise里面的输出直接执行
console.log(4); ......2
// resolve暂停跳出Promise
resolve();
}).then((res) => {
console.log(5); ......6
});
// 调用first函数,输出
first();
// 同步任务直接输出
console.log('6'); ......4
//输出顺序 1 4 first函数 6 promise 3 5 settimeout 2
await和resolve会暂停当前promise直到别的异步任务结束才继续执行。例如题中的new Promise
resolve后不继续向下执行,而是寻找其他同步任务,同步任务全部结束,寻找异步任务中的微任务,最后在执行new Promise .then的微任务,最后再寻找异步任务中的宏任务执行。
console.log(1);
async function asyFunction () {
console.log(2);
await console.log(3);
await console.log(4);
console.log(5);
return 6
}
new Promise((resolve, reject) => {
console.log(10);
resolve();
}).then(res => {
console.log(11);
})
console.log(7);
setTimeout(() => {
console.log(8)
}, 0)
setTimeout(() => {
console.log(9)
}, 1000)
asyFunction().then(res => { console.log(res) });
//输出结果 1 10 7 2 3 11 4 5 6 8 9
依次看代码,未执行的先别看, Promise.resolve().then(() ...微任务,放进堆中;setTimeout宏任务放进堆中,执行async1,回去看async1,输出1;await会隐式的生成promise,将后面的代码放进promise.then中,并执行本身,所以输出2,将3放进堆中;接着往下执行,输出6;3和4都为then,看代码执行顺序,所以是4,3;最后是宏任务5
async function async1 () {
console.log(1);
const result = await async2();
console.log(3);
}
async function async2 () {
console.log(2);
}
Promise.resolve().then(() => {
console.log(4);
});
setTimeout(() => {
console.log(5);
});
async1();
console.log(6);
//结果 1 2 6 4 3 5
setTimeout宏任务放进堆中,test未执行先别看;进入Promise输出2,遇到回调函数(微任务)放进堆中,往下走async2未执行继续往下走,执行test输出5,await紧跟的函数立即执行,隐式生成一个promise,后面的代码包裹在promise.then中成为微任务放进堆中,执行完test继续往下走,输出4,执行完代码回到堆中执行微任务,微任务根据代码的执行顺序依次执行,then的优先级大于finally(finally和async创建的.then属于第一次回调一个层级的
,finally后面的.then已经是第二次回调了所以放在下一级微任务里了)所以先输出3,6再输出8,执行完微任务执行宏任务
setTimeout(function () {
console.log('1');
});
async function test () {
console.log('5')
//隐式创建一个微任务 promise.then()
await async2();
console.log('6')
}
new Promise(function (resolve) {
console.log('2');
resolve();
}).then(function () {
console.log('3');
}).finally(() => {
console.log('8');
})
function async2 () {
console.log('7');
}
test()
console.log('4');
//结果:2、5、7、4、3、6、8、1