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
相关产品推荐
相关产品推荐

