You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Promise.all()比顺序await调用更快?

异步请求调度与顺序await适用场景解析

1. JavaScript内部如何调度Promise.all的并行请求?

JavaScript基于事件循环机制处理异步任务,Promise.all的并行调度逻辑可拆解为以下步骤:

  • 调用fetch时,浏览器会立即发起HTTP请求(此步骤由浏览器网络线程处理,不属于JavaScript主线程),同时返回一个处于pending状态的Promise。
  • Promise.all会同时触发所有传入的Promise(即两个fetch请求),这些请求在浏览器网络层并行处理,互不阻塞。
  • JavaScript主线程继续执行同步任务,直到遇到await关键字,此时async函数暂停执行,将控制权交还给事件循环。
  • 当所有fetch请求的响应返回后,对应的Promise变为resolved状态,结果被收集到微任务队列。
  • 事件循环处理完当前宏任务队列的所有任务后,依次执行微任务队列中的任务,此时await Promise.all(...)恢复执行,解构得到所有响应结果。

对比顺序await的差异:顺序执行时,必须等待第一个fetch的响应完全处理完成(包括解析JSON),才会发起第二个fetch请求,请求串行执行,总耗时为两个请求的时间之和。

2. 哪些场景下更适合使用顺序await调用?

以下场景优先选择顺序await而非并行请求:

  • 请求存在依赖关系:后续请求需要使用前一个请求的返回数据(比如第二个请求的参数是第一个请求返回的ID),此时必须等待前序请求完成才能发起后续请求。
  • 限流或避免服务器压力:当接口有请求频率限制,或者服务器资源有限时,串行请求可以避免短时间内发起大量请求导致的限流、报错或服务器负载过高。
  • 按需中断流程:如果前一个请求失败时,后续请求没有执行的必要,顺序await可以在第一个请求抛出错误时直接终止函数执行,无需发起后续请求;而Promise.all只要有一个Promise失败就会立即reject,但此时其他请求可能已经发起,无法取消。
  • 资源加载依赖:某些场景下需要确保前一个资源加载完成后再加载依赖它的资源(比如先加载配置文件,再根据配置加载对应的业务数据)。

实现代码

版本1:顺序执行的getToDos(较慢版本)

/**
 * 版本1: getToDos(较慢版本)
 * 此处请求按顺序执行。
 */
const getToDos = async () => {
    // 等待待办事项加载完成...
    const todoResponse = await fetch('https://jsonplaceholder.typicode.com/todos')
    const todos = await todoResponse.json()

    // ...之后才开始加载用户数据(耗时较长)
    const userResponse = await fetch('https://jsonplaceholder.typicode.com/users')
    const users = await userResponse.json()

    // 数据关联(合并)
    todos.forEach(t => {
        // 查找与待办事项userId匹配的用户
        t.user = users.find(u => u.id == t.userId)
    });

    return todos
}

版本2:并行执行的getTodo2(高效版本)

/**
 * 版本2: getTodo2(高效版本)
 * 此处利用并行性节省时间。
 */
const getTodo2 = async () => {
    // Promise.all同时启动两个请求。
    // [todosRes, usersRes]是解构赋值——结果直接分配。
    const [todosRes, usersRes] = await Promise.all([
        fetch('https://jsonplaceholder.typicode.com/todos'),
        fetch('https://jsonplaceholder.typicode.com/users')
    ]);

    // 将响应数据转换为真实JavaScript格式(JSON)
    const todos = await todosRes.json();
    const users = await usersRes.json();

    // 数据合并:为每个待办事项分配其所属用户
    todos.forEach(element => {
        element.user = users.find(user => user.id === element.userId);
    });

    return todos; // 返回最终的"超级数组"
};

展示函数:在网页上渲染数据

/**
 * 展示函数:在网页上显示数据
 */
const showToDos = async () => {
    // 1. 获取数据(我们使用快速的版本2)
    const todos = await getTodo2();
    
    // 2. 在HTML中找到"锚点"(<ul>元素)
    const todosElement = document.getElementById('todos');
    
    // 3. 遍历每个待办事项并构建HTML
    todos.forEach(t => {
        // 创建一个新的列表元素(尚不可见)
        const li = document.createElement('li');
        
        // 插入Bootstrap结构:
        // alert: 灰色边框 | form-check: 复选框样式 | badge: 名称标签
        li.innerHTML = `
        <div class="alert alert-light" role="alert">
            <div class="form-check">
                <input class="form-check-input" type="checkbox" ${t.completed ? 'checked' : ''} id="c-${t.id}">
                <label class="form-check-label" for="c-${t.id}">
                    ${t.title}
                    <span class="badge text-bg-secondary">${t.user.username}</span>
                </label>
            </div>
        </div>`;

        // 4. 添加交互性(复选框逻辑)
        // 在刚创建的li中查找复选框
        const checkbox = li.querySelector("input");

        // 事件监听器:响应复选框的勾选或取消
        checkbox.addEventListener("change", () => {
            // 同步复选框状态与我们的数据对象(t)
            t.completed = checkbox.checked;
            
            // 调试:在控制台显示更新后的对象
            console.log("状态已更改:", t);
        });

        // 5. 将完成的li添加到网页的列表中
        todosElement.appendChild(li);
    });
}

// 启动:页面加载时执行该函数
showToDos();

HTML页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>To Do List</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    
</head>
<body>
    <h1>To Do List</h1>
    <script src="app.js"></script>
   

    <ul id="todos"></ul>
</body>
</html>

内容的提问来源于stack exchange,提问作者Kerem Babo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 22:27:27