【问题标题】:Cannot figure out how to wait for Promise无法弄清楚如何等待 Promise
【发布时间】:2019-08-20 01:28:19
【问题描述】:

我有一个包含用户 ID 的数组,我需要找出每个 ID 所属的名称并将它们返回到一个数组中。 我可以从数据库中获取用户名,使用 knex 并将它们推送到一个数组中,但是当我尝试发送数据时,它总是一个空数组。

我不太擅长 Promises,所以不知道如何应用到我的项目中。

const userId = [10,11,12,13]
let users = []

userId.map(id => {
    db.select('name').from('users').where('user_id', id)
    .then(user => {
        users.push(user)
    })
})
res.json(users)

我希望响应等到循环完成并发送用户数组。

【问题讨论】:

标签: javascript node.js knex.js


【解决方案1】:

您的 map 正在创建一个 undefined 数组,因为您的回调函数不返回任何内容。如果我们稍微调整一下,它会创建一个 Promise 数组,这正是 Promise.all 所期望的。 :-) 所以:

const userId = [10,11,12,13]
Promise.all(
    userId.map(id => db.select('name').from('users').where('user_id', id))
)
.then(users => {    // `users` is an array of users, in the same order as the IDs
    res.json(users);
})
.catch(error => {
    // Render an error response
});

【讨论】:

【解决方案2】:

作为替代答案,您可以针对此特定查询进行 1 次数据库访问,这意味着您无需等待多个 Promise 并减少数据库负载

knex.raw(
  'select name from users where user_id in (' + userId.map(_ => '?').join(',') + ')', 
  [...userId]
);

【讨论】:

    【解决方案3】:

    首先你需要等待所有的promise完成后再运行res.json(...)

    其次,你不应该在 promise 解析后改变外部变量(promise 解析的顺序会改变你的输出,这不好。

    这样的东西应该可以正常工作

    const userId = [10,11,12,13]
    
    // map userId array to promise array
    // Promise.all aggregates a promise array into one big promise that resolves when all promises resolve (and preserves array order)
    Promise.all(
      userId.map(id =>
        db
          .select("name")
          .from("users")
          .where("user_id", id)
      )
    )
      .then(users => res.json(users))
      .catch(e => console.error("Error::", e));
    
    /*handle error in the catch block*/
    
    /* visual example of Promise.all.then block
    Promise.all([           users = [
       getUser(10),    ->     {userId: 10, ....}
       getUser(11),    ->     {userId: 11, ....}
       getUser(12)     ->     {userId: 12, ....}
    ])                      ]
    
    */
    
    

    【讨论】:

    • return 没用,可能会让 OP 感到困惑
    • @JonasWilms 取决于环境,有些人需要 return Promise 所以它不会挂起请求(例如 firebase 函数),但你是对的,习惯。
    【解决方案4】:

    你想要Promise.all(),见here

    试试

    const userId = [10,11,12,13]
    
    let users = userId.map(id => new Promise(resolve => {
        db.select('name').from('users').where('user_id', id)
        .then(user => {
            resolve(user)
        })
    }))
    Promise.all(users).then(()=>res.json(users))
    

    这里的users 是一系列承诺。解决所有问题后,立即执行res.json(users)

    【讨论】:

      猜你喜欢
      • 2021-05-17
      • 2014-12-18
      • 2013-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多