一、任务类型
- macro-task: script(整体代码)、
setTimeout、setInterval、setImmediate、I/O、UI rendering - micro-task: process.nextTick、Promise(这里指浏览器实现的原生 Promise)、Object.observe、MutationObserver、queueMicrotask
ajax请求不属于宏任务,js线程遇到ajax请求,会将请求交给对应的http线程处理,一旦请求返回结果,就会将对应的回调放入宏任务队列,等请求完成执行。
二、几个微任务宏任务小例子
(1)
setTimeout(function () {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("then1");
});
setTimeout(function () {
console.log("setTimeout2");
});
console.log(2);
queueMicrotask(() => {
console.log("queueMicrotask1")
});
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});
(2)
async function async1() {
console.log('async1 start')
// await异步函数的返回结果 resolve的结果会作为整个异步函数的promise的resolve结果->同步代码
// await后面的执行代码 就会变成.then后面的执行函数->微任务
// 也就是说 console.log('async1 end') 这一段是相当于then方法内的 会被加入微任务中
await async2();
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve();
}).then(function () {
console.log('promise2')
})
console.log('script end')
(3) 为什么直接返回直接返回Promise.resolve(4) 微任务推迟两次呢?NewPromiseResolveThenableJob
Promise.resolve().then(() => {
console.log(0);
//1.直接返回4 微任务不会做任何延迟
// return 4
//2.直接返回Promise.resolve(4) 微任务推迟两次
// return Promise.resolve(4);
//3.返回thenable对象
return {
then: ((resolve, reject) => {
resolve(4);
})
}
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() => {
console.log(6);
})
(4)nodejs 下的Event loop,微任务执行时nextTick优先执行
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout0')
}, 0)
setTimeout(function () {
console.log('setTimeout2')
}, 300)
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick1'));
async1();
process.nextTick(() => console.log('nextTick2'));
new Promise(function (resolve) {
console.log('promise1')
resolve();
console.log('promise2')
}).then(function () {
console.log('promise3')
})
console.log('script end')
三、微任务 宏任务执行顺序
我们梳理一下事件循环的执行机制:
循环首先从宏任务开始,遇到script,生成执行上下文,开始进入执行栈,可执行代码入栈,依次执行代码,调用完成出栈。
执行过程中遇到上边提到的调度者,会同步执行调度者,由调度者将其负责的任务(回调函数)放到对应的任务队列中,直到主执行栈清空,然后开始执行微任务的任务队列。微任务也清空后,再次从宏任务开始,一直循环这一过程。
四、工作中遇到的一个应用场景 一个页面的多个组件,同时发送n个请求,请求顺序不确定,如何控制请求的发送顺序?