Node.js .map 函数导致 express 服务器提前 return 响应对象

Node.js .map function causing express server to return the response object early

我的目标是为 Node 上的 express 运行 创建一个抽象的 POST 函数,类似于 Django 的内置 REST 方法。作为我抽象的 POST 函数的一部分,我正在检查数据库 (mongo) 中的有效外键、重复项等...,这就是我们在此过程中所处的位置。下面的函数实际上是第一次调用 mongo 来检查传入的外键是否确实存在于它们应该存在的 tables/collections 中。

简而言之,本机 .map 函数内的内置响应功能似乎导致了 called/subsidiary 函数的早期 return,但仍在 called/subsidiary 在早期 return 发生后起作用。

代码如下:

const db = require(`../../models`)

const findInDB_by_id = async params => {

  console.log(`querying db`)

  const records = await Promise.all(Object.keys(params).map(function(table){
    return db[table].find({
      _id: {
        $in: params[table]._ids
      }
    })
  }))
  console.log('done querying the db')

  // do stuff with records
  return records
}

// call await findIndDB_by_id and do other stuff
// eventually return the response object

这是服务器日志

querying db
POST <route> <status code> 49.810 ms - 9 //<- and this is the appropriate response
done querying the db
... other stuff

当我修改函数以便 map 函数不 return 任何东西时,(a) 它不查询数据库,并且 (b) 不 return尽早表达回应对象。所以通过修改这个:

const records = await Promise.all(Object.keys(params).map(function(table){
    return db[table].find({ // going to delete the `return` command here
      _id: {
        $in: params[table]._ids
      }
    })
  }))

至此

const records = await Promise.all(Object.keys(params).map(function(table){
    db[table].find({ // not returning this out of map
      _id: {
        $in: params[table]._ids
      }
    })
  }))

服务器日志更改为:

querying db
done querying the db
... other stuff
POST <route> <status code> 49.810 ms - 9 // <-appropriate reponse

但是我实际上并没有构建我的查询,所以查询响应是空的。我遇到这种行为,匿名地图函数也是这种格式的箭头函数 .map(table => (...))

有什么想法、原因或建议吗?

你应该尝试像当它遇到第一个异步函数时它开始执行其余代码的东西

let promiseArr = []
Object.keys(params).map(function(table){
     promiseArr.push(db[table].find({
      _id: {
        $in: params[table]._ids
      }
    }))
  })

let [records] = await Promise.all(promiseArr)

如果您仍想使用地图方法

await Promise.all(Object.keys(params).map(async function(table){
    return await db[table].find({ 
      _id: {
        $in: params[table]._ids
      }
    })
  })
)

您的第一个代码版本按预期工作并且日志符合预期。

所有async函数return一个承诺。所以 findInDB_by_id() 永远是 return 一个承诺。事实上,当调用代码继续 运行 时,一旦遇到函数内部的第一个 await,它们就会 return 承诺。调用代码本身需要使用 await.then() 从该承诺中获取已解析的值。

然后,一段时间后,当您在该函数中执行 return someValue 时,someValue 将成为该承诺的已解决值,并且该承诺将得到解决,从而通知调用代码通过 await.then() 最终结果现已准备就绪。

await 只暂停执行它所在的 async 函数。它根本不会导致调用者被阻塞。调用者仍然必须处理 return 来自 async 函数的承诺。


您的代码的第二个版本只是 运行s 数据库查询开环,无法控制,也无法收集结果或处理错误。这通常被称为“发射后不管”。您的其余代码将继续执行,而不考虑那些数据库查询中发生的任何事情。第二版代码是正确的可能性很小。虽然在极少数情况下“即发即弃”是合适的,但我总是希望至少在这种情况下记录错误,但由于看起来你想要结果,所以这是不正确的