Javascript承诺链地狱

Javascript承诺链地狱,javascript,node.js,Javascript,Node.js,我不知道如何解决承诺链的问题。我的代码摘要:我为特定用户执行mongoose查询,获取他的CarID,然后查询每辆车的详细信息,并通过JSON响应返回这些详细信息 let carsDetails = []; User.findById(userId) .then(user => { const carIds = user.carsDetails; carIds.forEach((carId) => { Car.findById(c

我不知道如何解决承诺链的问题。我的代码摘要:我为特定用户执行mongoose查询,获取他的CarID,然后查询每辆车的详细信息,并通过JSON响应返回这些详细信息

let carsDetails = [];

  User.findById(userId)
    .then(user => {
      const carIds = user.carsDetails;
      carIds.forEach((carId) => {
        Car.findById(carId)
          .then(car => {
            console.log(car);
            carsDetails.push(car);     
          })
          .catch(err => { throw err; });
        });

      return res.status(200).json({ data: carsDetails });
    })
    .catch(error => {
      throw error;
    });

问题是没有汽车被实际推到carsDetails.pushcar上的carsDetails数组上;行,因为它在填充数组之前跳转到return语句。是否有一种解决方法可以执行这些查询并以数组、对象…的形式返回结果。。。?我也尝试过用自制的AsyncForEach语句以AsyncWait形式编写所有内容,但这对我没有帮助。有什么建议吗?我已经试过了,但没有解决问题。谢谢

您需要收集Car.findbyidcandcalls的承诺,并使用Promise.all等待所有承诺,然后再回复。您可以使用array.map将每个ID映射到Car.findById中的承诺


您需要收集Car.findbyidcandcalls的承诺,并使用Promise.all等待所有承诺,然后再回复。您可以使用array.map将每个ID映射到Car.findById中的承诺

await/async是一种方式,使用await/async您可以使用常规的。。。而不是forEach

异步函数getCardDetails{ 让carsDetails=[]; let user=await user.findByIduserId; const carIds=user.carsDetails; 让龋齿的龋齿{ let car=等待car.findbyidcrad 控制台、行车记录仪; carsdeails.pushcar; } 返回res.status200.json{ 数据:carsDetails }; } 或者你用Promise.all和map代替。。。的

这两种解决方案略有不同。带有映射的第二个版本将立即将所有请求发送到DB,然后等待,直到所有请求都得到解决。第一个将一个接一个地发送请求。哪一个更好取决于用例,第二个可能导致请求偷窥,并且可能更容易被DDoS滥用。

等待/异步是一种方法,使用常规的等待/异步。。。而不是forEach

异步函数getCardDetails{ 让carsDetails=[]; let user=await user.findByIduserId; const carIds=user.carsDetails; 让龋齿的龋齿{ let car=等待car.findbyidcrad 控制台、行车记录仪; carsdeails.pushcar; } 返回res.status200.json{ 数据:carsDetails }; } 或者你用Promise.all和map代替。。。的


这两种解决方案略有不同。带有映射的第二个版本将立即将所有请求发送到DB,然后等待,直到所有请求都得到解决。第一个将一个接一个地发送请求。哪一个更好取决于用例,第二个可能导致请求偷窥,并且可能更容易被DDoS滥用。

如果您可以找到很多车,您可能希望在单个请求中执行查询,而无需堆叠多个承诺:

User.findById(userId)
  .then(user => {
    const carIds = user.carsDetails; 
    // if carsDetails is not an array of objectIds do this instead :
    // const carIds = user.carsDetails.map(id => mongoose.Types.ObjectId(id));
    return Car.find({ _id: { $in: carIds });
  })
  .then(userCars => {
    res.status(200).json({ data: userCars })
  })

如果您可以找到很多车,您可能希望在单个请求中执行查询,而无需堆叠多个承诺:

User.findById(userId)
  .then(user => {
    const carIds = user.carsDetails; 
    // if carsDetails is not an array of objectIds do this instead :
    // const carIds = user.carsDetails.map(id => mongoose.Types.ObjectId(id));
    return Car.find({ _id: { $in: carIds });
  })
  .then(userCars => {
    res.status(200).json({ data: userCars })
  })

尝试使用async/await解决此问题。它将更加可读和清晰

async function getCarDetail() {
  let carsDetails = []

  try {
    const user = await User.findById(userId)
    const carIds = user.carsDetails

    for (let i = 0; i < carIds.length; i++) {
      const carId = carIds[i]

      const car = await Car.findById(carId)
      carsDetails.push(car)
    }

    return res.status(200).json({ data: carsDetails })

  } catch(error) {
    console.log(error)
  }
}

尝试使用async/await解决此问题。它将更加可读和清晰

async function getCarDetail() {
  let carsDetails = []

  try {
    const user = await User.findById(userId)
    const carIds = user.carsDetails

    for (let i = 0; i < carIds.length; i++) {
      const carId = carIds[i]

      const car = await Car.findById(carId)
      carsDetails.push(car)
    }

    return res.status(200).json({ data: carsDetails })

  } catch(error) {
    console.log(error)
  }
}

我也尝试过用async await格式编写所有东西,使用自制的async forEach语句,您应该展示您在那里尝试过的内容,因为await/async是一种方式,使用refular的await/async。。。如果它不能正常工作,那么你可能没有正确地使用它。我也尝试过用async Wait的形式编写所有东西,使用自制的async forEach语句,你应该展示你在那里尝试过的东西,因为Wait/async是一种方式,而使用refular的Wait/async。。。of循环而不是forEach.Promise.all,如果它不起作用,那么您可能没有正确使用它。请解释为什么第二种方法是better@AvcS它不一定更好,它是不同的。第二种方法将立即向数据库发送所有请求。请解释为什么第二种方法是better@AvcS它不一定更好,它是不同的。第二个将立即将所有请求发送到db.Car.find{{u id:{$in:carIds}肯定比使用带有Promise的map要好。all,因为它很可能是由DB作为一个查询处理的。这是所有查询中最理想的解决方案。我认为我使用Promise的方式是错误的,但$in选择器确实做得最好。谢谢!一个.catch处理程序会让它更好。@ambianBeing当然,我只想指出一点指出写入.catcherror=>{throw error;};与不写入任何内容相同。catcherror=>{throw error;};毫无用处,因为它除了重试错误之外什么都不做。最好是写入。thenuserCars=>{res.status200.json{data:userCars}.catchnext假设它是express和midde的第三个agrument
使用lware@ambianBeingCar.find{u id:{$in:carIds}肯定比使用带有Promise的map要好。all,因为它很可能是由DB作为一个查询处理的。这是所有查询中最理想的解决方案。我认为我使用Promise的方式是错误的,但$in选择器确实做得最好。谢谢!一个.catch处理程序会让它更好。@ambianBeing当然,我只想指出一点指出写入.catcherror=>{throw error;};与不写入任何内容相同。catcherror=>{throw error;};毫无用处,因为它除了重试错误之外什么都不做。最好是写入。thenuserCars=>{res.status200.json{data:userCars}.catchnext假设它是express,并且使用了中间件的第三个agrument next。@ambianBeingI对可读和干净没有相同的定义,嵌套try/catch块对meI来说非常糟糕没有相同的可读和干净定义,嵌套try/catch块对我来说非常糟糕