Promise未及时触发?`Cannot read properties of undefined (reading 'then')`问题排查
问题描述
遇到Promise未及时resolve的问题,无法理解原因——自己的函数并非异步,想要实现遍历整个数组,仅在所有元素验证完成后再resolve Promise。
每当满足resolve条件时,会调用promiseHelper = Promise.resolve(value),但出现Cannot read properties of undefined (reading 'then')错误。尽管promiseHelper.then写在递归函数之后,按道理promiseHelper应该在执行then语句前已被resolve。
疑问:为何该变量到达代码的这一部分时并非Promise?实现此类功能的更佳方案是什么?
原代码:
const cart = req.body.items; //Array of items let promiseHelper; function recursiveCheck(cartIndex){ let pieceOutOfStock = Piece.find({nombre: cart[cartIndex].name, cantidad: {$gte:cart[cartIndex].amount}}); pieceOutOfStock.then(response =>{ if (!response.length){ //If nothing on the query, resolve as false console.log("not enough:", element.amount, response.length); // 此处element应为cart[cartIndex] promiseHelper = Promise.resolve(false); return false; } else{ if(cart.length > cartIndex+1){ //If something on the query and items left, validate next item recursiveCheck(cartIndex+1); } else{ //if last item, resolve as true promiseHelper = Promise.resolve(true); return true; } } }) } function getStock(){ return new Promise (resolve =>{ recursiveCheck(0); promiseHelper.then(response =>{ if(!response){ resolve("reject") } else{ resolve("All good") } }) }) } getStock().then(async response =>{ //do some stuff })
问题原因
- 异步执行顺序问题:
Piece.find()是异步数据库操作(返回Promise),它的.then()回调会在当前调用栈执行完毕后才触发。而getStock()里调用recursiveCheck(0)后,立刻执行promiseHelper.then(),此时promiseHelper还未被赋值(仍是初始的undefined),自然会报错无法读取then属性。 - 对异步的误解:你的函数虽然没有用
async声明,但内部调用了异步操作,整个验证流程本质是异步的,不能用同步逻辑处理。 - 递归逻辑隐患:即使
promiseHelper被赋值,递归调用的多个异步回调可能会覆盖它的值,导致结果不可控。
更佳实现方案
方案1:并行验证(效率更高)
所有商品库存检查并行执行,只要有一个不满足就返回失败:
async function getStock() { const cart = req.body.items; // 生成所有库存检查的Promise数组 const checkPromises = cart.map(item => { return Piece.find({ nombre: item.name, cantidad: { $gte: item.amount } }).then(response => { if (!response.length) { console.log("not enough:", item.amount, response.length); throw new Error("reject"); // 抛出错误标记验证失败 } }); }); try { await Promise.all(checkPromises); // 等待所有验证完成 return "All good"; } catch (err) { return err.message; // 返回失败信息 } } // 使用方式 getStock().then(response => { // do some stuff });
方案2:串行验证(逐个检查)
逐个验证商品,前面的商品不满足时直接停止后续检查:
async function getStock() { const cart = req.body.items; for (const item of cart) { const response = await Piece.find({ nombre: item.name, cantidad: { $gte: item.amount } }); if (!response.length) { console.log("not enough:", item.amount, response.length); return "reject"; } } return "All good"; } // 使用方式 getStock().then(response => { // do some stuff });
方案3:修正递归逻辑(仅作理解参考)
如果坚持用递归,需让递归函数返回Promise,保证异步流程顺序:
function recursiveCheck(cartIndex) { const cart = req.body.items; if (cartIndex >= cart.length) { return Promise.resolve(true); // 所有验证完成 } return Piece.find({ nombre: cart[cartIndex].name, cantidad: { $gte: cart[cartIndex].amount } }).then(response => { if (!response.length) { console.log("not enough:", cart[cartIndex].amount, response.length); return Promise.resolve(false); } // 递归调用下一个,返回Promise链 return recursiveCheck(cartIndex + 1); }); } function getStock() { return recursiveCheck(0).then(response => { return response ? "All good" : "reject"; }); } // 使用方式 getStock().then(response => { // do some stuff });
内容的提问来源于stack exchange,提问作者peareon
相关产品推荐
相关产品推荐

