一.任务队列
- JS的执行我们可以看成是任务队列,所有的操作以任务的形式出现在任务队列中
- 任务一共包括两种,分别是同步任务和异步任务
- 不管是同步还是异步,JS都会按顺序执行,只是不等待异步的执行结果
同步任务
除异步任务外的任务我们称之为同步任务,同步任务按顺序执行,没有优先级
异步任务
异步任务包含微任务(microtask)和宏任务(macrotask),有优先级之分,先执行微任务,后执行宏任务
- 微任务:promise async await
- 宏任务:setTimeout setInterval
二.eventloop
- 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)
- 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件(注册一个回调函数)
- 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",将每个事件(一个接一个)对应的回调放入执行栈中,然后执行回调内的同步代码
- 主线程不断重复上面的第三步
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
三.事件循环案例
// 案例1
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
new Promise((resolve, reject) => {
console.log(4);
resolve();
}).then(() => {
console.log(5);
})
// 1 3 4 5 2
// 案例2
setTimeout(() => {
console.log(1);
new Promise((resolve, reject) => {
resolve();
}).then(function () {
console.log(2);
})
}, 0);
// 1 2
// 案例3
setTimeout(() => {
console.log(1);
}, 0);
setTimeout(() => {
console.log(2);
}, 0);
setTimeout(() => {
console.log(3);
}, 50);
// 1 2 3
// 案例4
setTimeout(() => {
console.log(1);
new Promise((resolve, reject) => {
resolve();
}).then(function () {
console.log(2);
})
}, 0);
console.log(5);
new Promise((resolve, reject) => {
resolve();
}).then(function () {
console.log(3);
setTimeout(() => {
console.log(4);
}, 0)
});
// 5 3 1 2 4
// 案例5 以上代码上下交换
new Promise((resolve, reject) => {
resolve();
}).then(function () {
console.log(3);
setTimeout(() => {
console.log(4);
}, 0)
})
console.log(5);
setTimeout(() => {
console.log(1);
new Promise((resolve, reject) => {
resolve();
}).then(function () {
console.log(2);
})
}, 0);
// 5 3 1 2 4
四.今日头条面试题
async function async1() {
console.log(1);
await async2();
console.log(2);
}
async function async2() {
console.log(3);
}
console.log(4);
setTimeout(function () {
console.log(5);
}, 0)
async1();
new Promise(function (resolve) {
console.log(6);
resolve();
}).then(function () {
console.log(7);
});
console.log(8);
// 4 1 3 6 8 2 7 5