KeystoneJS回调函数数据赋值到数组的问题求助
解决KeystoneJS中异步回调导致关联数据无法正确返回的问题
嘿,我完全懂你现在的困境——异步回调的时序问题真的是Node.js新手绕不开的一个坑!你代码里的核心问题是:getAgenda是异步操作,但你在调用它之后立刻就把还没被赋值的agen_arrpush进mainarray了,等回调函数执行的时候,mainarray已经被返回给前端,自然拿不到关联数据。
下面给你两个解决方案,优先推荐第一个,代码更简洁易维护:
方案一:用async/await重构代码(推荐)
现代Node.js已经全面支持async/await,它能把异步代码写成类似同步的逻辑,彻底避免回调嵌套的混乱。
首先重构getAgenda函数,让它返回Promise:
const getAgenda = async (id) => { if (!id) return []; // 先获取所有关联的AgendaDay const agendaDays = await AgendaDay.model.find({ summit: id }).exec(); const agendaData = []; // 遍历每个AgendaDay,获取对应的AgendaItem for (const day of agendaDays) { const items = await AgendaItem.model.find({ agendaDay: day._id }).exec(); // 把Item数据整理成需要的格式 const itemList = items.map(item => ({ item_id: item._id, item_name: item.name, from_time: item.time_from, to_time: item.time_to, desc: item.description, featured: item.featured // 注意你原代码里拼写错了fatured,这里修正了 })); agendaData.push({ name: day.name, date: day.date, description: day.description, item_list: itemList }); } return agendaData; };
然后重构exports.list接口,同样用async/await:
exports.list = async (req, res) => { try { // 获取所有Summit数据 const summits = await Summit.model.find().exec(); if (!summits) return res.json('not found'); // 原代码里查询了Guest但没用到,如果你不需要可以删掉这行 // const guests = await Guest.model.find().exec(); const mainarray = []; // 遍历每个Summit,等待getAgenda返回数据后再push for (const summit of summits) { const agendaArr = await getAgenda(summit._id); mainarray.push({ id: summit._id, name: summit.name, agenda_data: agendaArr, }); } // 所有数据都准备好后再返回 res.json({ summit: mainarray }); } catch (err) { // 统一处理错误 res.json({ err: err }); } };
为什么这样改?
async/await会暂停代码执行,直到异步操作完成,保证你在push到mainarray之前已经拿到了完整的关联数据- 用
for...of遍历数组,配合await可以确保每个Summit的关联数据都加载完成后再处理下一个 - 代码结构更清晰,避免了多层回调嵌套(也就是所谓的“回调地狱”)
方案二:用Promise.all处理并行异步(性能优化版)
如果你的Summit数量很多,上面的串行遍历可能会慢一点,这时候可以用Promise.all让所有getAgenda请求并行执行:
exports.list = async (req, res) => { try { const summits = await Summit.model.find().exec(); if (!summits) return res.json('not found'); // 并行获取所有Summit的关联数据 const summitPromises = summits.map(async (summit) => { const agendaArr = await getAgenda(summit._id); return { id: summit._id, name: summit.name, agenda_data: agendaArr, }; }); // 等待所有Promise完成 const mainarray = await Promise.all(summitPromises); res.json({ summit: mainarray }); } catch (err) { res.json({ err: err }); } };
额外提示
- 原代码里
Guest.model.find()查询后没有使用,建议删掉,减少不必要的数据库查询 - 注意拼写错误:
fatured应该是featured,已经在重构代码里修正了 - 如果你的KeystoneJS版本非常旧,不支持
exec()返回Promise,可以用Node.js内置的util.promisify方法把回调风格的方法转换成Promise风格
内容的提问来源于stack exchange,提问作者Kasun
相关产品推荐
相关产品推荐

