执行代码的先后顺序:
先 主任务 后 任务队列。
任务队列又分:微任务(Microtasks)、宏任务(task)
- 微任务:先注册的任务先执行(先进先出)。比如:Promise.then 、process.nextTick
- 宏任务:比如:整体代码
<script>
、ajax、定时器(比如:setTimeout)、事件(比如:onclick)、requestAnimationFrame(帧动画)、I/O(文件操作)、UI rendering(样式渲染)
任务队列既有宏任务又有微任务,先执行微任务,再执行宏任务。
主任务(主线程,执行完之后会去任务队列里读取可执行的任务进入主线程) ↓ 任务队列:微任务(清空一次) ------> 宏任务(每执行一个清空一次微任务) ↑_________循环执行________|
这种循环机制叫做:事件循环(event loop)
主线程-微任务-宏任务 练习:(如何使用async、await、Promise以及各种任务的执行特点)
async function fn() {
console.log(1);
let b = await fn2();//b拿到return的值 = resolve()里面的值,并阻塞下面的代码。
console.log(b);
console.log(2)//出现在await之后,也就是2一定跟着3之后出现
};
function fn2() {
return new Promise((resolve, reject) => {//async、await要配合Promise使用。
console.log(9);
setTimeout(() => {
resolve(3)//进入宏任务,定时器谁先触发谁先执行。
}, 1000)
});
}
// async function fn() {
// //function fn() {
// console.log(1);
// let b = await fn2();
// console.log(2)//进入微任务,谁先进入谁先触发。
// };
// function fn2() {
// console.log(9);
// setTimeout(() => {
// resolve(3)//进入宏任务,定时器谁先触发谁先执行。
// }, 1000)
// };
setTimeout(() => {
console.log(6)//进入宏任务
}, 500);
fn()
let a = new Promise((resolve, reject) => {
console.log(4);
resolve()
})
a.then(() => {
console.log(5)//进入微任务
});
//fn()
console.log(8);
//1,9,4,8,2,5,3,6
//4,1,9,8,5,2,3,6
//注:如果await后面的函数,没有被Promise包着。 await 下面的代码会进微任务队列(谁先进入谁先执行),定时器会进宏任务队列(谁先触发谁先执行)。
//1,9,4,8,5,6,3,2
//await后面的函数被Promise包着,那么await后面的函数才会阻塞下面的函数,等await后面的函数执行完,再往下执行(只在函数体内发生)。
面试题一:
let body = document.body;
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(1);
});
console.log(2);
});
body.addEventListener('click', function () {
Promise.resolve().then(() => {
console.log(3);
});
console.log(4);
});
面试题二:
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('setTimeout');
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
console.log('script end');
思考?await 下面被阻断的代码,那这一部分代码是如何执行的?
- await 后面如果是微任务(一个promise),它下面的代码就会等待这个微任务执行完,紧跟着执行。
- await 后面如果是主任务(比如一个函数或一个表达式),其下面的代码就会等待这一批主任务执行完,最后执行。