【问题标题】:How to Promise.all for nested arrays?如何 Promise.all 用于嵌套数组?
【发布时间】:2019-03-30 07:31:09
【问题描述】:

数据结构:

tasks: [
  {
    name: "get milk",
    users: ["abc", "def"]
  },
  {
    name: "buy bread",
    users: ["def", "ghi"]
  }
]

我需要从数据库中获取每个用户的电子邮件地址(到目前为止一切顺利)并等待所有任务完成,然后继续处理数据。不起作用的地方写在下面的cmets中:

var tasks_with_emails = tasks.map(function(task) {
  var emails = task.users.map(function(user) {
    return user_to_email(user); // from the database
  });
  Promise.all(emails).then(function(emails) {
    task.emails = emails;
    console.log(task); // this one works fine
    return task;
  }).catch(next);
});
Promise.all(tasks_with_emails).then(function(tasks) {
  console.log(tasks); // <==== this one fires too quickly
}).catch(next);

所以tasks_with_email 应该先等待所有嵌套的emails 解决,但事实并非如此。

【问题讨论】:

  • 我相信您缺少Promise.all(emails) 的退货声明。尝试在 Promise.all(email) 前面添加一个 return
  • tasks_with_emails 是一个由undefineds 组成的数组
  • 由于您没有从 tasks_with_emails 内部返回 Promise.all(),正如 Oleksii 指出的那样,Promise.all(tasks_with_emails) 立即解析,因为 tasks_with_emails 是一个不包含任何承诺的数组。
  • @OleksiiRudenko 刚刚尝试过,同样的结果:tasks_with_emails is an array of 2 null
  • @trs 可能会尝试将tasks.map 中的函数提取到一个命名函数中,看看它是否在那里失败。您在Promise.all 中返回task,但它可能会失败,在这种情况下,您希望至少在没有电子邮件的情况下返回tasks

标签: javascript arrays asynchronous promise bluebird


【解决方案1】:

Promise.all() 前面添加返回后,您的代码对我有效,如下例所示。 所以看看user_to_email() 返回什么。这应该是一个可以解析为电子邮件字符串的承诺。

const user_to_email = user => new Promise(( resolve, reject ) => {
  setTimeout(() => resolve( `${ user }@example.com` ), 3000 );
});
const tasks  = [
  {
  name: "get milk",
  users: ["abc", "def"]
  },
  {
  name: "buy bread",
  users: ["def", "ghi"]
  }
];
const tasks_with_emails = tasks.map( task => {
  const emails = task.users.map( user => {
    return user_to_email(user); // from the database
  });
  return Promise.all(emails).then( emails => {
    task.emails = emails;
    return task;
  });
});
Promise.all(tasks_with_emails).then( tasks => {
  console.log(tasks); // <==== this one fires too quickly
});
setTimeout(() => console.log( '1000ms' ), 1000 );
setTimeout(() => console.log( '2000ms' ), 2000 );
setTimeout(() => console.log( '2999ms' ), 2999 );

【讨论】:

  • 原来问题完全出在其他地方,但是在 Promise.all() 前面添加 return 确实可以解决它。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 2018-05-11
  • 1970-01-01
  • 2021-04-28
  • 1970-01-01
相关资源
最近更新 更多