在 for 循环中承诺

Promise inside a for loop

我正在尝试使用承诺的 mysql 库进行一系列数据库插入和选择。

问题是我必须使用 for 循环。

我的代码如下所示:

var partNumber = [],
        stageName = [],
        quantity = [],
        locationName = []
    var orderType, receiveDate, customerName

    pool.query(`select * from orderDetail where orderID = ${req.body.orderID} order by orderDetailID`)
        .then(mainrow => {
            
            for (let i = 0; i < mainrow.length; i++) {
                
                    quantity.push(mainrow[i].QtyShipped)
                     pool.query(`Select PartNumber from parts where partID = ${mainrow[i].PartID}`)

                    .then(rows => {
                        console.log(`here is 1`)
                        partNumber.push(rows[0].PartNumber)
                    
                        return pool.query(`Select StageName from stages where StageID = ${mainrow[i].StageID}`)
                    })
                    .then(rows => {
                        console.log(`here is 2`)
                        
                        return pool.query(`Select LocationName from locations where locationID =${mainrow[i].LocationID}`)
                    })
                    .then(rows=>{
                        console.log(` here is 3`)
                        locationName.push(rows[0].LocationName)
                        
                        stageName.push(rows[0].LocationName)
                        orderType=mainrow[i].OrderType
                        receiveDate = mainrow[0].receiveDate
                        req.flash('success', `You returned back to the OrderID ${req.body.orderID}`)
                        customerName = mainrow[0].CustomerName
                        if(i==mainrow.length-1){
                            var query = queryString.stringify({
                                "orderID": req.body.orderID,
                                "orderType": orderType,
                                "date": receiveDate,
                                "customerName": customerName,
                                "success": req.flash('success'),
                                "partNumber": partNumber,
                                "quantity": quantity,
                                "locationName": locationName,
                                "stageName": stageName
                
                            })
                            
                            res.redirect('/orderDetails?' + query)
                            
                        }
                        
                    })
                    .catch(err => {
                        console.log(err)
                    })

                    
            }
            
        })
        

        .catch(err => {
            console.log(err)
        })

父查询是我检索 orderID 的地方,我循环遍历各种 orderID 以检索 orderDetails 并填充数组。但是,我真的很难在 for 循环中保持此代码同步。

我希望 console.log 是:

here is 1
here is 2
here is 3

here is 1
here is 2 
here is 3

here is 1
here is 2 
here is 3 

相反,我得到:

here is 1
here is 2
here is 1
here is 1
 here is 3
here is 2
here is 2
 here is 3
 here is 3

在这种情况下,每个异步代码都执行了正确的次数 3 但由于 for 循环,它根本不是同步的。有没有办法在 for 循环中使用异步代码并使其同步?

for 循环立即完成所有迭代,进行所有顶级查询。

当您到达 for 循环的末尾时,后台运行的异步数据库请求与迭代次数一样多。

无法保证在后续迭代的承诺得到解决之前,第一次迭代的所有承诺都得到解决。

简而言之,for 循环不会等到任何承诺被解决。

解决方案——使用async/await

for (let i = 0; i < mainrow.length; i++) {

   await pool.query(foo);
   await pool.query(bar);
}

这是一种(也是最受欢迎的)解决方法。

这是您用 async/await 重写的代码。请记住,使用这种方法,您将一个接一个地执行每个请求,而不是像使用 promises 那样并行执行。所以这个解决方案比较慢。同样正如 zero298 指出的那样,您应该使用准备好的语句来避免 SQL 注入。

const partNumber = []
const stageName = []
const quantity = []
const locationName = []
let orderType, receiveDate, customerName
try {
  const mainrow = await pool.query(`select * from orderDetail where orderID = ${req.body.orderID} order by orderDetailID`)
  for (let i = 0; i < mainrow.length; i++) {
    quantity.push(mainrow[i].QtyShipped)
    let rows = await pool.query(`Select PartNumber from parts where partID = ${mainrow[i].PartID}`)
    console.log(`here is 1`)
    partNumber.push(rows[0].PartNumber)
    rows = await pool.query(`Select StageName from stages where StageID = ${mainrow[i].StageID}`)
    console.log(`here is 2`)
    rows = await pool.query(`Select LocationName from locations where locationID =${mainrow[i].LocationID}`)
    console.log(` here is 3`)
    locationName.push(rows[0].LocationName)
    stageName.push(rows[0].LocationName)
    orderType = mainrow[i].OrderType
    receiveDate = mainrow[0].receiveDate
    req.flash('success', `You returned back to the OrderID ${req.body.orderID}`)
    customerName = mainrow[0].CustomerName
  }
  const query = queryString.stringify({
    "orderID": req.body.orderID,
    "orderType": orderType,
    "date": receiveDate,
    "customerName": customerName,
    "success": req.flash('success'),
    "partNumber": partNumber,
    "quantity": quantity,
    "locationName": locationName,
    "stageName": stageName

  })
  res.redirect('/orderDetails?' + query)
} catch(err) {
  console.log(err)
}