JS中的Promise和async、await

内容分享3小时前发布
0 0 0

一、先理清核心关系

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();

这里的关键逻辑:

  1. ipcRenderer.invoke('ping') 本身返回 Promise;
  2. async 修饰 func 函数,让其成为异步函数;
  3. await 等待 Promise 完成,直接获取 pong 结果;
  4. 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(需转译或高版本环境)

六、核心总结

  1. Promise:解决了回调地狱,将异步操作封装成可管理的对象,提供统一的状态和错误处理;
  2. async/await:简化 Promise 的调用写法,让异步代码 “同步化”,是目前 JavaScript 异步编程的主流方式;
  3. 关系:async/await 依赖 Promise 存在,没有 Promise 就无法使用 async/await;
  4. 实战原则:简单异步操作:可直接用 Promise;复杂异步逻辑(如多层依赖、需要顺序执行):优先用 async/await;错误处理:Promise 用 .catch(),async/await 用 try/catch(必须加,否则错误会静默失败)。
© 版权声明

相关文章

暂无评论

none
暂无评论...