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

Promise.all阻塞Fetch调用,如何实现aggregateSearch非阻塞执行?

问题:如何让aggregateSearch非阻塞,优先完成购物车更新?

我通过FETCH API调用远程接口,代码实现如下:

document.addEventListener("DOMContentLoaded", () => {
    loadCart();
    aggregateSearch("france", ["api1", "api2"]);
});

const aggregateSearch = async (term, AvailableApis) => {
    console.log("aggregateSearch")
    await Promise.all(AvailableApis.map((api) => {
        fetchApi(api, term);
    }))
};

const fetchApi = async (api, term) => {
    console.log("fetchApi");
    const aggregateRawResponse = await fetch('aggregate.php', { method: 'POST', body: JSON.stringify({ source: api, term: term }) });
    const aggregateResponse = await aggregateRawResponse.json();

    console.log('response from API done');

    document.getElementById('myDiv' + api)?.innerHTML = aggregateResponse.formattedResponse;
}

const updateCartCount = async () => {
    console.log("update cartcount"); // 该行已执行
    const fetchNbPhotos = await fetch("count.php");
    const data = await fetchNbPhotos.json();
    console.log("cart count done");
    document.getElementById('cartCounter').innerHTML = parseInt(data["nb"]); // 仅在aggregateSearch完成后执行
}

const loadCart = () => {
    console.log("start loading cart");
    fetch('cart.php')
    .then((response) => {
        return response.text();
    })
    .then((html) => {
        console.log("loading cart is done updating cart count");
        document.getElementById('cart')?.innerHTML = html
        updateCartCount();
    });
}

控制台输出:

start loading cart
aggregateSearch
fetchApi
loading cart is done updating cart count
update cartcount
cart count done
response from API done

API内容获取功能运行正常,但将购物车内容加载到cart容器、更新cartCounter容器的操作,需等待aggregateSearch执行完成后才会进行。尝试将loadCart改为async/await写法,未解决问题。

如何让aggregateSearch实现非阻塞,在API请求处于等待状态时就能更新cartCounter容器?

编辑
尝试将aggregateSearch修改为如下形式:

const aggregateSearch = async (term, AvailableApis) => {
    console.log("aggregateSearch")
    await Promise.all(AvailableApis.map((api) => {
        setTimeout(() => fetchApi(api, fulltext, []), 100);
        //fetchApi(api, fulltext, []);
    }))
};

此时cartCounter容器能立即更新。

编辑2
可复现场景中,控制台输出:

"start loading cart"
"aggregateSearch"
"update cartcount"
"response from API done"
"cart count done"

由于fetchApi设置了2000ms延迟,loadCart和updateCartCount均设置为100ms延迟,预期控制台输出应为:

"start loading cart"
"aggregateSearch"
"update cartcount"
"cart count done"
"response from API done"

解决方案

核心问题有两个:前端代码的Promise处理错误,以及可能存在的PHP会话锁导致请求串行。

1. 修正前端Promise处理

aggregateSearch中的Promise.all调用存在错误:map的回调函数没有返回fetchApi的Promise,导致Promise.all等待的是一堆undefined,虽然Promise.all会立即完成,但fetchApi的同步执行部分会抢占主线程,同时后续的API请求可能因为服务器端的串行处理被阻塞。

修正后的aggregateSearch代码:

const aggregateSearch = async (term, AvailableApis) => {
    console.log("aggregateSearch")
    // 关键:返回fetchApi的Promise给map,确保Promise.all正确追踪异步任务
    await Promise.all(AvailableApis.map((api) => fetchApi(api, term)));
};

修正后,Promise.all会正确等待所有API请求完成,但await会主动让出主线程,不会阻塞购物车更新的异步任务执行。

2. 解决PHP会话锁问题(关键原因)

如果后端是PHP,默认情况下会话使用文件锁,同一个会话的多个请求会被串行处理——也就是说,当aggregate.php的请求先发起并持有会话锁时,cart.php和count.php的请求必须等待它释放锁才能执行,这就导致购物车更新被阻塞。

解决办法是在每个PHP脚本中,完成会话数据读取后立即关闭会话,释放锁:

session_start();
// 读取所需的会话数据(比如用户ID等)
$userId = $_SESSION['user_id'];
// 立即关闭会话,释放锁
session_write_close();

// 后续的业务逻辑处理

这样多个请求就能并行处理,购物车的更新请求不会被API请求阻塞。

为什么加setTimeout能临时生效?

setTimeout会把fetchApi的调用推迟到下一个事件循环,让购物车的请求先发起并抢占会话锁,从而避开了串行阻塞的问题,但这只是临时的规避方案,不是根本解决办法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 01:21:03