JS事件循环和Promise, async/await
我们都知道JavaScript 是单线程语言。JS 最初设计用于操作 DOM,若多线程同时修改 DOM 会导致冲突(如一个线程删 DOM、一个线程改 DOM)。但通过事件循环可以实现非阻塞异步操作(如网络请求、定时器、DOM 事件)。
JS事件循环
我们都知道JavaScript 是单线程语言。JS 最初设计用于操作 DOM,若多线程同时修改 DOM 会导致冲突(如一个线程删 DOM、一个线程改 DOM)。
但通过事件循环可以实现非阻塞异步操作(如网络请求、定时器、DOM 事件)。
事件循环的核心
| 组件 | 作用 | 存储内容 |
|---|---|---|
| 调用栈(Call Stack) | 同步代码、异步回调函数的 “执行栈”(LIFO 后进先出) | 正在执行的同步函数、待执行的异步回调函数 |
| 宏任务队列(Macro Task Queue) | 存储待执行的 “宏任务”(异步操作的回调) | 定时器(setTimeout/setInterval)、DOM 事件、AJAX 请求、setImmediate(Node 特有)、UI 渲染 |
| 微任务队列(Micro Task Queue) | 存储待执行的 “微任务”(优先级高于宏任务的异步回调) | promise.then/catch/finally、queueMicrotask、process.nextTick(Node 特有,优先级最高) |
事件循环的执行流程(前端浏览器环境)
- 执行同步代码:调用栈清空同步代码(同步函数依次入栈执行,执行完出栈);
- 执行所有微任务:同步代码执行完后,检查微任务队列,将所有微任务依次入栈执行(执行完一个出栈,直到微任务队列为空);
- 执行 UI 渲染(浏览器特有):微任务执行完后,浏览器会进行一次 UI 渲染(如 DOM 更新);
- 执行一个宏任务:从宏任务队列取出队首的一个宏任务,入栈执行;
- 重复循环:回到步骤 2,直到所有队列清空。
console.log("1. 同步代码开始");
setTimeout(() => {
console.log("2. 宏任务:setTimeout 回调");
Promise.resolve().then(() => console.log("3. 宏任务内的微任务"));
}, 0);
Promise.resolve().then(() => {
console.log("4. 微任务:Promise.then");
setTimeout(() => console.log("5. 微任务内的宏任务"), 0);
});
console.log("6. 同步代码结束");
//以上代码输出
//1. 同步代码开始
//6. 同步代码结束
//4. 微任务:Promise.then
//2. 宏任务:setTimeout 回调
//3. 宏任务内的微任务
//5. 微任务内的宏任务
Promise, async/await
Promise 和 async/await 是 JavaScript 中处理异步操作的核心方案 ——Promise 解决了传统回调地狱问题,async/await 则是 Promise 的语法糖,让异步代码写法更接近同步,可读性更高。
Promise 基础(核心原理与用法)
Promise 是一个对象,代表异步操作的 “最终完成(或失败)及其结果值”。
1. Promise 的三种状态
pending(等待中):初始状态,异步操作未完成;
fulfilled(已成功):异步操作完成,返回结果值;
rejected(已失败):异步操作出错,返回错误信息。
状态不可逆:一旦从 pending 转为 fulfilled 或 rejected,状态就固定不变。
2. Promise 基本用法
(1)创建 Promise 对象
通过 new Promise((resolve, reject) => { … }) 创建,传入一个 “执行器函数”,函数有两个参数:
resolve(value):异步成功时调用,将状态转为 fulfilled,并传递结果值;
reject(error):异步失败时调用,将状态转为 rejected,并传递错误信息。
function fetchData(url) {
return new Promise((resolve, reject) => {
// 模拟异步操作(如 AJAX 请求)
setTimeout(() => {
const success = true;
if (success) {
const data = { code: 200, message: "成功" };
resolve(data); // 成功:调用 resolve 传递结果
} else {
const error = new Error("请求失败");
reject(error); // 失败:调用 reject 传递错误
}
}, 1000);
});
}
(2)消费 Promise:then() / catch() / finally()
创建 Promise 后,通过以下方法处理结果:
then(onFulfilled):状态为 fulfilled 时执行,接收 resolve 传递的值;
catch(onRejected):状态为 rejected 时执行,接收 reject 传递的错误;
finally(onFinally):无论成功 / 失败,最终都会执行(如关闭加载动画)。
fetchData("https://api.example.com")
.then(data => {
console.log("请求成功:", data);
return data.message; // 可返回值,供下一个 then 接收
})
.then(message => console.log("处理结果:", message))
.catch(err => console.error("请求失败:", err))
.finally(() => console.log("请求结束(无论成功/失败)"));
.then 支持两个可选参数
promise.then(
onFulfilled, // 状态变为 fulfilled(成功)时执行,接收 resolve 的值
onRejected // 状态变为 rejected(失败)时执行,接收 reject 的错误
);
这是 Promise 原生支持的 “成功 + 失败” 回调写法,无需依赖 catch;
而 catch(onRejected) 本质是 then(null, onRejected) 的语法糖 —— 专门处理失败,不关心成功。
虽然 then 支持双参数,但实际开发中更推荐then 只处理成功,catch 统一捕获所有错误 ,原因:
代码更清晰:成功逻辑和失败逻辑分离,避免回调嵌套;
捕获更全面:catch 能捕获前面所有环节的错误(包括 then 成功回调的代码错误);
调试更方便:统一的错误处理点,便于日志打印和错误监控。
(3)Promise 静态方法(常用)
Promise.resolve(value):快速创建一个已成功的 Promise;
Promise.reject(error):快速创建一个已失败的 Promise;
Promise.all(iterable):接收多个 Promise 数组,全部成功才返回(结果为数组),一个失败则整体失败;
Promise.race(iterable):接收多个 Promise 数组,第一个完成的结果(无论成功 / 失败)作为最终结果;
Promise.allSettled(iterable):接收多个 Promise 数组,所有操作完成后返回(结果包含每个 Promise 的成功 / 失败状态)。
async/await 基础(Promise 的语法糖)
async/await 是 ES2017 引入的语法,基于 Promise 实现,核心作用是让异步代码同步化写法。
- 核心语法规则
async:修饰函数,表明该函数是异步函数,返回值自动包装为 Promise;
await:只能在 async 函数内部使用,用于 “等待” 一个 Promise 完成(阻塞当前 async 函数执行,不阻塞主线程);
错误处理:用 try/catch 捕获 await 后的 Promise 错误(替代 catch())。
async function getCommentsByAsyncAwait() {
try {
const user = await fetchUser();
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts[0].id);
return comments;
} catch (err) {
console.error(err);
}
}
Promise 与 async/await 的区别与联系
async/await 是 Promise 的语法糖,底层依赖 Promise 实现;
所有 async/await 代码都可以改写为 Promise 链式调用,反之亦然;
await 本质上是 “等待 Promise 状态变更” 的语法简化。
使用场景:
- 简单异步逻辑(如单个请求):用 Promise 或 async/await 均可;
- 复杂异步逻辑(多步骤依赖、需调试):优先用 async/await;
- 并行异步操作:必须结合 Promise.all/Promise.race 等静态方法;
更多推荐

所有评论(0)