下文以如何回答面试做过总结,想要深入promise和event loop => # JS执行机制你了解多少?一文详解事件循环、微任务、宏任务
Promise回忆
Promise 是同步的,但 .then
或 .catch
是异步执行的。
pending
:初始状态,等待中。fulfilled
:操作成功完成。rejected
:操作失败。
- 执行机制 :
- Promise 接收一个执行器函数,该函数会同步立即执行 ,并接收两个参数:
resolve
和reject
,用于改变 Promise 的状态。 .then
用于处理成功或失败的结果,.catch
专门处理失败,.finally
无论成功或失败都会执行。
- Promise 接收一个执行器函数,该函数会同步立即执行 ,并接收两个参数:
- 链式调用 :
- 每次
.then
或.catch
都会返回一个新的 Promise,支持链式调用。 - 重要方法 :
Promise.all(iterable)
:并发执行多个 Promise,全部成功时返回结果数组;若有一个失败,则返回第一个失败的结果。Promise.race(iterable)
:返回第一个完成的 Promise 结果(无论成功或失败)。Promise.allSettled(iterable)
:并发执行多个 Promise,无论成功或失败都返回结果数组。
- 每次
js
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
Promise.all([p1, p2])
.then(values => console.log(values)); // [1, 2]
Promise.race([p1, p2])
.then(value => console.log(value)); // 1
手写promise.all
js
const PromiseAll = (promises) => {
return new Promise((resolve,reject) => {
let count = 0;
let res = [];
if(promises.length === 0) return resolve(res)
promises.forEach((item,index) => {
Promise.resolve(item)
.then(data => {
res[index] = data;
count++; // 循环次数
// 都完成 调用resolve
if(count === promises.length) {
resolve(res)
}
})
.catch(err => {
reject(err)
})
})
})
}
可以自己写个 demo:异步按顺序读取三个文件. 使用promise异步 要求每次promise返回,可以使用es6
面题:async/await 和promise,用哪个多
- Promise:提供了丰富的异步操作方法,适合处理多个异步任务。简单异步操作,方便维护
- async/await :基于 Promise,使用类似同步的方式处理异步操作。
async
标识异步函数,await
将后面的任务作为微任务放入微任务队列。结合try...catch...finally
,代码更易维护。
event loop
在开发中,我们会遇到一些异步操作,比如发起网络请求,进行文件读写,或设定定时器等。这些操作使用同步进行执行,可能导致主线程阻塞,造成程序卡顿。这时候,我们可以使用event loop
event loop 本质是一种循环机制,执行异步代码并且管理调用栈和任务队列之间的交互,确保异步任务正常进行。 他会先创建一个全局执行上下文,按顺序执行完全局代码;再不断循环检查微任务队列,如果有任务,全部执行完,将异步任务放入主线程进行执行;再查任务队列,是否有像定时器,i/o等异步任务完成操作进行任务队列,不断重复。
【执行上下文】包含要执行代码和运行需要的信息(词法环境)。执行完成,被弹出栈并且销毁(垃圾回收机制)
总结来讲: Event Loop 是 JavaScript 处理异步任务的核心机制。
- 背景:在开发中,异步操作(如网络请求、文件读写、定时器等)如果同步执行,会导致主线程阻塞,程序卡顿。Event Loop 通过循环机制管理调用栈和任务队列,确保异步任务正常执行。
- 执行流程 :
- 创建全局执行上下文,按顺序执行全局代码。
- 检查微任务队列,执行所有微任务。
- 将异步任务(如定时器、I/O)放入任务队列,按优先级执行。
- 重复上述过程,直到任务队列为空。
执行顺序:同步代码 -> 微任务队列 -> 宏任务队列 -> 进入 idle 状态。
微任务与宏任务
-
微任务:
Promise.then
、MutationObserver
、process.nextTick
。- 微任务在当前任务结束后立即执行,优先级高于宏任务。
- process.nextTick() 在微任务中优先,在当前操作完成后立即执行,不会进入事件循环的下一个阶段
- try catch finlly 后面可以看做是promise.then 方法
- MutationObserver 用于监听 DOM 的变化,当 DOM 发生变化时,它的回调函数会被触发。它的执行顺序优先于宏任务,但低于同步代码和其他微任务(如
Promise.then
)
-
宏任务:
setTimeout
、setInterval
、setImmediate
。- 宏任务在事件循环的下一个阶段执行。
面试考察event loop怎么思考
个人做法:
- 1,先全局执行上下文有哪些代码,打印处理
- 2,遇到微任务,放入微任务队列,执行完;如果调用了其他函数,查看是否是微任务或同步代码,是直接执行;如果是宏任务,等待完成后放入任务队列。
- 3,任务队列,就按压入事件进行操作。比如,0s 定时比1s先压入,即便1s 代码在前面
- 但总得了解哪些是宏,哪些是微任务
可以做做下面面试题
js
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => {
console.log('4');
});
process.nextTick(() => {
console.log('3');
});
});
Promise.resolve().then(() => {
console.log('5');
});
setTimeout(() => {
console.log('7');
});
setImmediate(() => {
console.log('9');
});
console.log('6');
当然大佬可以挑战下面event loop 题,可在评论区留下你的讨论
js
console.log(1);
setTimeout(() => {
console.log(2);
},1000);
new Promise((resolve) => {
// 1s 后调用resolve,promise状态变成fulfilled 触发`.then()`回调打印 3
setTimeout(resolve,1000,3)
}).then((value) => {
console.log(value);
}).then(() => {
console.log(4);
});
async function async1() {
try {
const v1 = await new Promise((resolve) => {
resolve(7);
});
console.log(v1);
await async2()
}catch(e) {
console.log(e);
}finally{
console.log(8);
}
console.log(9);
}
async1()
async function async2() {
console.log(5);
throw 6;
}
console.log(10);,
┻┳|・ω・)问我? 关注点赞,有更多精彩内容,咋们不见不散