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

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
})
问题原因
  1. 异步执行顺序问题:Piece.find()是异步数据库操作(返回Promise),它的.then()回调会在当前调用栈执行完毕后才触发。而getStock()里调用recursiveCheck(0)后,立刻执行promiseHelper.then(),此时promiseHelper还未被赋值(仍是初始的undefined),自然会报错无法读取then属性。
  2. 对异步的误解:你的函数虽然没有用async声明,但内部调用了异步操作,整个验证流程本质是异步的,不能用同步逻辑处理。
  3. 递归逻辑隐患:即使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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 07:20:04