串行请求太慢?1个Promise.all并发技巧,前端接口效率直接翻倍

0 阅读4分钟

😩前端必踩痛点:串行await拖慢页面加载

写前端接口联调时,很多新手会这么写: 多个无依赖接口,挨个await等待,第一个请求结束,才发第二个。 页面白屏时间直接翻倍,用户加载体验极差。

比如同时拉取语录+必应壁纸两个接口,串行写法要等两次请求总时长,并发只需最慢接口的耗时。

读完这篇你能学到:

  1. Promise三种状态流转与不可逆特性
  2. Promise.all核心执行逻辑、失败兜底规则
  3. 完整可运行前端并发请求实战代码
  4. Promise.all高频踩坑点与优化方案
  5. 串行/并发接口适用场景区分

屏幕截图 2026-06-20 191425.png

一、先搞懂Promise基础状态,看懂并发底层逻辑

1. Promise三种固定状态

创建实例:new Promise(),初始状态为 pending(待处理) 最终只会两种终态,状态一旦确定,永久无法变更

  • fulfilled(成功):执行.then(),拿到返回结果
  • rejected(失败):执行.catch(),捕获报错信息

2. Promise.all核心失败机制

接收Promise数组作为参数,执行规则:

  1. 所有请求全部成功,才会把结果按数组原始顺序返回
  2. 只要任意一个Promise失败,整体直接失败,立刻进入catch,不会等待其余未完成请求

二、实战场景:无依赖接口并发请求

需求:页面初始化同时拉取两条独立接口

  1. 一言语录接口:https://v1.hitokoto.cn/?c=i&encode=json
  2. 必应每日壁纸接口:https://api.1314.cool/bingimg/?type=json&rand=1

两个接口无数据依赖,完全不需要串行等待,用Promise.all实现并发。

完整可运行HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise.all并发请求实战</title>
</head>
<body>
<script>
// 封装两个独立接口请求函数
const getStory = async () => 
    fetch('https://v1.hitokoto.cn/?c=i&encode=json')

const getRatp = async () => 
    fetch('https://api.1314.cool/bingimg/?type=json&rand=1')

async function main() {
    // 串行写法(低效,不推荐)
    // const storyRes = await getStory();
    // const imgRes = await getRatp();

    // Promise.all 并发执行
    Promise.all([getStory(), getRatp()])
    .then(responseList => {
        // responseList 顺序和传入Promise数组完全对应
        // 批量解析所有接口返回的json数据
        return Promise.all(responseList.map(res => res.json()))
    })
    .then(data => {
        console.log('语录数据:', data[0])
        console.log('壁纸数据:', data[1])
    })
    .catch(err => {
        // 任意接口报错,直接进入这里
        console.log('请求失败:', err)
    })
}

// 执行并发请求
main();
</script>
</body>
</html>

代码核心逻辑拆解

  1. 把所有fetch Promise放进数组,传入Promise.all,同时发起网络请求
  2. 接口返回的response数组,顺序永远和传入数组保持一致,不会因为接口响应快慢打乱顺序
  3. 全部接口请求完成后,统一调用.map批量解析json()
  4. 任意接口异常,直接触发catch终止流程

三、Promise.all三大高频踩坑提醒

坑1:单一接口报错,全部数据直接丢失

问题:多个接口并发,其中一个404/500,catch直接捕获,成功的接口数据也拿不到。 解决:每个Promise内部单独捕获异常,保证不中断整体流程:

const wrapFetch = (fn) => fn().catch(err => ({ error: true, msg: err }))

Promise.all([wrapFetch(getStory), wrapFetch(getRatp)])

坑2:混淆串行与并发,白白浪费加载时间

错误写法(串行,耗时叠加):

// 总耗时 = 接口1耗时 + 接口2耗时
const a = await getStory()
const b = await getRatp()

正确写法(并发,耗时取最大值):

// 总耗时 = 最慢接口耗时
const [a, b] = await Promise.all([getStory(), getRatp()])

坑3:忘记response.json()异步解析,直接打印response对象

fetch返回的是Response包装对象,不是业务数据,必须通过.json()二次解析,且该方法同样返回Promise,需要二次Promise.all批量处理。

四、什么时候用并发,什么时候只能串行?

✅ 优先使用Promise.all并发

  • 接口之间无数据依赖,互不影响
  • 页面初始化批量拉取字典、列表、配置类数据
  • 批量上传、批量查询接口

❌ 必须串行await

  • 第二个接口需要第一个接口返回的id/token作为参数
  • 接口调用有严格先后业务流程(登录→获取用户信息)

五、总结

  1. Promise存在pending/fulfilled/rejected三种状态,状态切换不可逆;
  2. Promise.all实现无依赖接口并发,大幅缩短页面加载时长;
  3. 失败策略:任一Promise报错,整体直接失败,需单独兜底处理异常;
  4. 返回结果顺序固定,和传入Promise数组顺序一一对应,不受接口响应速度影响。

简单一句话:无依赖接口全用Promise.all并发,有数据依赖再用await串行