Promise与async/await的接口串联和并联

实际业务中,我们常会遇到两种典型场景:一是接口间存在依赖关系,需按顺序执行(串联调用);二是接口间相互独立,可并行执行以提升效率(并联调用)。

目前主流的异步处理方案有两种:Promise.then 链式调用与 async/await 同步化语法。本文将结合业务场景,讲解两种方案在串联、并联调用中的实现方式。

1、Promise

Promise 是 JavaScript 异步编程的核心规范,解决了传统回调地狱问题。其核心能力在于:通过 then 方法实现异步逻辑的链式串联。

1.1 Promise实现并联调用

无依赖关系的接口可同时发起请求,无需等待彼此完成,总耗时取决于最慢的接口(而非所有接口耗时之和)。但需注意:直接调用接口仅能实现 "并行发起",若需统一处理结果或错误,必须配合 Promise.all。

场景:页面初始化时,需同时加载三个独立数据:商品列表、用户信息、购物车数据,无任何依赖关系。

基础并联:仅并行发起请求(无统一处理)

若无需等待所有接口完成,仅需各自返回后执行独立逻辑,可直接调用接口函数:

js 复制代码
// 模拟接口请求函数
function fetchGoods() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("商品列表获取成功");
      resolve([{ id: 1, name: "商品A" }, { id: 2, name: "商品B" }]);
    }, 1500);
  });
}

function fetchUserInfo() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("用户信息获取成功");
      resolve({ id: 100, name: "李四" });
    }, 1000);
  });
}

function fetchCart() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("购物车数据获取成功");
      resolve([{ goodsId: 1, count: 2 }, { goodsId: 2, count: 1 }]);
    }, 2000);
  });
}

// 直接并行发起请求,各自处理结果

fetchGoods().then(goods => renderGoodsList(goods)); // 渲染商品列表

fetchUserInfo().then(user => renderUserAvatar(user)); // 渲染用户头像

fetchCart().then(cart => renderCartCount(cart)); // 渲染购物车数量

进阶并联:用 Promise.all 统一处理结果与错误

若后续逻辑依赖所有接口的返回数据,或需统一处理错误(如任意接口失败则显示 "加载失败"),则需使用 Promise.all

js 复制代码
// 并联调用:使用 Promise.all() 同时执行
Promise.all([fetchGoods(), fetchUserInfo(), fetchCart()])
  .then(([goods, user, cart]) => {
    // 所有接口都成功后,统一处理结果(总耗时取决于最慢的接口,这里是2秒)
    console.log("所有请求完成,结果汇总:");
    console.log("商品列表:", goods);
    console.log("用户信息:", user);
    console.log("购物车数据:", cart);
    
    // 统一执行后续逻辑(如渲染完整页面)
    renderDashboard(goods, user, cart);
  })
  .catch(error => {
    // 只要有一个接口失败,就会立即触发(失败快速反馈)
    console.error("至少一个请求失败:", error);
  });

1.2 Promise实现串联调用

利用 then 方法的链式特性,前一个接口的返回结果作为后一个接口的入参,确保接口按顺序执行。其关键在于:then 回调中返回的 Promise 实例,会将状态与结果传递给下一个 then。

场景:需按顺序获取数据:先获取用户信息(拿到 userId)→ 用 userId 获取订单列表(拿到 orderId)→ 用 orderId 获取订单详情,接口间存在依赖。

js 复制代码
// 模拟接口请求函数
function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("获取用户信息成功");
      resolve({ userId: 1001, name: "张三" }); // 返回用户信息
    }, 1000);
  });
}

function fetchOrders(userId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`根据用户ID=${userId}获取订单列表成功`);
      resolve([{ orderId: 2001, goods: "手机" }, { orderId: 2002, goods: "电脑" }]); // 返回订单列表
    }, 1000);
  });
}

function fetchOrderDetail(orderId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`根据订单ID=${orderId}获取订单详情成功`);
      resolve({ orderId, price: 5999, status: "已付款" }); // 返回订单详情
    }, 1000);
  });
}

// 串联调用:使用 .then() 链式执行
fetchUser()
  .then(user => {
    // 第一个接口完成后,调用第二个接口(传入用户ID)
    return fetchOrders(user.userId);
  })
  .then(orders => {
    // 第二个接口完成后,调用第三个接口(传入第一个订单ID)
    return fetchOrderDetail(orders[0].orderId);
  })
  .then(detail => {
    // 第三个接口完成后,处理最终结果
    console.log("最终订单详情:", detail);
  })
  .catch(error => {
    // 捕获整个链条中的错误
    console.error("请求失败:", error);
  });

2、async/await

async/await 是基于 Promise 实现的语法糖,核心优势是将异步代码 "同步化"。await关键字的意思是"等待",表示其后面的表达式需要等待,返回完成后再向下继续,代码结构更清晰,避免了 then 链式调用的嵌套感。

2.1 async/await实现串联调用

在 async 函数中,通过 await 关键字逐个等待接口完成,前一个接口的结果可直接作为后一个接口的参数,逻辑与同步代码完全一致。

场景:同 Promise 串联场景,依次获取用户信息 → 订单列表 → 订单详情

js 复制代码
// 复用模拟接口函数(与 Promise 示例一致)
function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("获取用户信息成功");
      resolve({ userId: 1001, name: "张三" });
    }, 1000);
  });
}

function fetchOrders(userId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`根据用户ID=${userId}获取订单列表成功`);
      resolve([{ orderId: 2001, goods: "手机" }, { orderId: 2002, goods: "电脑" }]);
    }, 1000);
  });
}

function fetchOrderDetail(orderId) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`根据订单ID=${orderId}获取订单详情成功`);
      resolve({ orderId, price: 5999, status: "已付款" });
    }, 1000);
  });
}

// async/await 串联调用
async function fetchDataInSeries() {
  try {
    // 第一步:获取用户信息(等待完成后再执行下一步)
    const user = await fetchUser();
    
    // 第二步:用用户ID获取订单列表(依赖上一步结果)
    const orders = await fetchOrders(user.userId);
    
    // 第三步:用订单ID获取详情(依赖上一步结果)
    const detail = await fetchOrderDetail(orders[0].orderId);
    
    // 所有步骤完成后处理结果
    console.log("最终订单详情:", detail);
  } catch (error) {
    // 统一捕获整个串联过程中的错误(任何一步失败都会进入这里)
    console.error("请求失败:", error);
  }
}

// 执行函数
fetchDataInSeries();

2.2 async/await实现并联调用

async/await 本身不支持直接并行。这里仅给出使用async/await实现Promise.all进行统一处理的范例。

场景:同Promise并联场景,同时获取商品列表、用户信息、购物车数据。

js 复制代码
// async/await 并联调用(结合 Promise.all)
async function fetchDataInParallel() {
  try {
    // 等待所有请求完成(总耗时取决于最慢的接口,这里是2秒)
    const [goods, user, cart] = await Promise.all([fetchGoods(), fetchUserInfo(), fetchCart()]);
    
    // 统一处理所有结果
    console.log("所有请求完成,结果汇总:");
    console.log("商品列表:", goods);
    console.log("用户信息:", user);
    console.log("购物车数据:", cart);
  } catch (error) {
    // 任意一个请求失败,都会进入这里
    console.error("至少一个请求失败:", error);
  }
}

// 执行函数
fetchDataInParallel();

总结

Promiseasync/await都可以实现接口的串联和并联调用。并联调用直接进行多个接口的并发调用即可,如果需要对接口返回的数据进行统一处理,则需要配合Promise.all。而对于串联调用,async/await的同步化语法,使代码的线性排列与同步逻辑一致,可读性更高,是更好的调用方式。

相关推荐
流星稍逝3 小时前
前端解决两数计算精度确实问题
前端
stringwu3 小时前
Flutter 中的 MVVM 架构实现指南
前端·flutter
俩毛豆3 小时前
【页面路由导航】三步实现页面跳转的完整示例
前端·harmonyos
Happy coder3 小时前
【avalonia教程】17mvvm简介、command
前端·javascript·vue.js
喵叔哟3 小时前
9. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--Web API 接口与前端集成:把能力对外开放
前端·.net
烟袅3 小时前
CSS Animation 全面解析:从入门到实战,打造丝滑动效
前端·css
前端西瓜哥4 小时前
平面几何:多边线光滑化处理
前端
老前端的功夫4 小时前
Webpack 优化:你的构建速度其实还能快10倍
前端·javascript
Holin_浩霖4 小时前
React渲染原理学习笔记
前端