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

Express API返回数组偶缺最后项,需用async/await优化异步请求逻辑

API端点响应数组缺失最后一项的异步处理修复

问题根源

你的代码里,https.request是异步回调式操作,通过if (i == books.length -1)触发响应的逻辑存在致命问题:循环是同步执行的,所有请求会被快速发起,但它们的响应完成顺序完全不确定——最后一个请求的end事件(也就是填充书名到results的逻辑)可能还没执行,你就已经发送了响应,导致返回的数组缺失最后一项。

修复方案

把每个Google Books API请求包装成Promise,用Promise.all等待所有请求完成后再统一返回响应,确保所有数据都获取完毕后才输出结果。

修复后的完整代码

//GET a user's books with notes
const getNotebooks = async (req, res) => {
    // ... 你的其他前置代码

    const books = await Book.find({ userId }).sort({ createdAt: -1 }); // 获取用户所有笔记本书籍数组

    // 将HTTPS请求封装为Promise,支持async/await调用
    const fetchBookTitle = (gId) => {
        return new Promise((resolve, reject) => {
            const request = https.request(apiUrl + gId, (response) => {
                let data = '';
                response.on('data', (chunk) => {
                    data += chunk.toString();
                });
                response.on('end', () => {
                    try {
                        const body = JSON.parse(data);
                        resolve(body.volumeInfo.title);
                    } catch (parseErr) {
                        reject(parseErr);
                    }
                });
            });
            request.on('error', reject);
            request.end();
        });
    };

    try {
        // 用Promise.all等待所有请求完成,自动保持原books数组的顺序
        const results = await Promise.all(books.map(async (book) => {
            const title = await fetchBookTitle(book.gId);
            return {
                id: book.userId,
                gId: book.gId,
                title: title
            };
        }));

        res.status(200).json(results);
    } catch (error) {
        console.error('请求出错:', error);
        res.status(400).json({ error: error.message });
    }
};

关键改动说明

  • Promise封装异步请求:把基于回调的https.request转为Promise,让单个请求的结果可以用await等待,避免回调嵌套和时序混乱。
  • Promise.all批量处理:通过books.map生成所有请求的Promise数组,Promise.all会等待所有请求完成后返回有序结果,完全保证结果顺序和原books数组一致。
  • 统一错误处理:用try/catch包裹所有异步操作,单个请求失败时会直接进入catch块,避免端点崩溃,同时返回清晰的错误信息。
  • 消除共享变量风险:原代码中共享的results数组可能因异步并发修改导致数据异常,现在每个请求独立生成结果对象,由Promise.all自动组装,彻底避免这类问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:55:18