一、先理清核心关系
Promise 是 JavaScript 处理异步操作的基础对象,而 async/await 是 ES2017 推出的、基于 Promise 的语法糖(简化 Promise 调用的写法)。三者的核心目标都是解决 JavaScript 异步编程的回调地狱问题,让异步代码更易读、易维护。
二、Promise:异步操作的 “容器”
1. 核心作用
Promise 是一个代表异步操作最终结果的对象:
- 它将异步操作(如网络请求、文件读写、Electron 的 IPC 通信)封装成一个可管理的对象;
- 解决了传统 “回调地狱”(多层嵌套回调函数)的问题,让异步逻辑线性化;
- 提供统一的异步错误处理机制。
2. 核心特性
- 三种状态(状态一旦改变,永久不可逆):pending(进行中):初始状态;fulfilled(已成功):异步操作完成;rejected(已失败):异步操作出错。
- 两个关键方法:resolve:将状态从 pending 改为 fulfilled,并传递成功结果;reject:将状态从 pending 改为 rejected,并传递错误信息。
3. 基本用法(结合之前的 Electron IPC 例子)
js
// 模拟主进程 ping 操作的 Promise 封装
function ping() {
// 返回一个 Promise 对象
return new Promise((resolve, reject) => {
// 异步操作(列如 IPC 通信、网络请求)
setTimeout(() => {
const success = true; // 模拟操作成功/失败
if (success) {
resolve('pong'); // 成功:传递结果
} else {
reject(new Error('ping 失败')); // 失败:传递错误
}
}, 1000);
});
}
// 调用 Promise
ping()
.then((response) => {
console.log('成功:', response); // 输出「成功:pong」
})
.catch((err) => {
console.error('失败:', err); // 失败时执行
})
.finally(() => {
console.log('无论成功失败都执行'); // 可选:最终清理逻辑
});
4. 核心价值
- 避免回调地狱:传统回调嵌套(如 fs.readFile 嵌套)会导致代码横向膨胀,Promise 通过 .then() 链式调用让逻辑纵向展开;
- 统一错误处理:.catch() 可捕获整个链式调用中任意一步的错误,无需为每个回调单独写错误处理;
- 异步操作组合:提供 Promise.all()(所有异步完成)、Promise.race()(最快完成的异步)等方法,方便管理多个异步操作。
三、async/await:Promise 的 “语法糖”
1. 核心作用
async/await 让异步代码看起来像同步代码,完全替代 .then() 链式调用,大幅降低异步代码的阅读和编写成本。
2. 核心规则
- async:修饰函数,表明该函数是异步函数,返回值会自动包装成 Promise(即使返回普通值);
- await:只能在 async 函数内使用,作用是 “暂停” 函数执行,等待 Promise 状态变为 fulfilled 并获取结果;若 Promise 被 rejected,await 会抛出错误,需用 try/catch 捕获。
3. 基本用法(改写上面的 Promise 例子)
js
// 异步函数(async 修饰)
async function callPing() {
try {
// await 等待 Promise 完成,并直接获取结果
const response = await ping();
console.log('成功:', response); // 输出「成功:pong」
} catch (err) {
console.error('失败:', err); // 捕获 Promise 失败的错误
} finally {
console.log('无论成功失败都执行');
}
}
// 调用异步函数
callPing();
4. 关键特性
- 同步式写法:去掉了 .then() 嵌套,代码逻辑和同步代码一致,更易读;
- 错误处理:通过 try/catch 捕获错误(和同步代码的错误处理方式一致);
- 非阻塞:await 仅暂停当前 async 函数的执行,不会阻塞整个 JavaScript 主线程;
- 返回值自动包装:async 函数的返回值会被包装成 Promise,列如:
- js
- async function test() { return 123; // 等价于 return Promise.resolve(123) } test().then(res => console.log(res)); // 输出 123
四、结合 Electron 场景的实战例子(回顾之前的 ping/pong)
js
// preload.js 中暴露的 ping 方法(返回 Promise)
ping: async () => await ipcRenderer.invoke('ping')
// 渲染进程中用 async/await 调用(核心场景)
async function func() {
try {
// await 等待 ipcRenderer.invoke('ping') 这个 Promise 完成
const response = await window.versions.ping();
console.log(response); // 打印 pong
} catch (err) {
console.error('调用失败:', err);
}
}
func();
这里的关键逻辑:
- ipcRenderer.invoke('ping') 本身返回 Promise;
- async 修饰 func 函数,让其成为异步函数;
- await 等待 Promise 完成,直接获取 pong 结果;
- try/catch 捕获 IPC 通信失败的错误(列如主进程未注册 ping 处理函数)。
五、Promise vs async/await 对比
|
特性 |
Promise |
async/await |
|
本质 |
异步操作的对象封装 |
基于 Promise 的语法糖 |
|
写法 |
链式调用(.then ().catch ()) |
同步式写法(try/catch) |
|
错误处理 |
.catch () 捕获链式错误 |
try/catch 捕获错误(更符合直觉) |
|
适用场景 |
简单异步操作、多个异步组合(all/race) |
复杂异步逻辑(多层依赖)、需要同步式阅读 |
|
兼容性 |
ES6(IE 不支持,需 polyfill) |
ES2017(需转译或高版本环境) |
六、核心总结
- Promise:解决了回调地狱,将异步操作封装成可管理的对象,提供统一的状态和错误处理;
- async/await:简化 Promise 的调用写法,让异步代码 “同步化”,是目前 JavaScript 异步编程的主流方式;
- 关系:async/await 依赖 Promise 存在,没有 Promise 就无法使用 async/await;
- 实战原则:简单异步操作:可直接用 Promise;复杂异步逻辑(如多层依赖、需要顺序执行):优先用 async/await;错误处理:Promise 用 .catch(),async/await 用 try/catch(必须加,否则错误会静默失败)。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...


