【问题标题】:How to wait for a promise to resolve inside a map?如何等待在地图内解决的承诺?
【发布时间】:2019-12-02 10:58:00
【问题描述】:

我有一个我想要处理的对象列表。该对象被传递给一个 Promise 函数,该函数执行此操作并解析回来。该过程可以是即时的,也可以不是即时的,具体取决于先前缓存的值。如果已经有计算值,它将立即解决。否则,它将计算。现在我遇到的问题是在计算第一个对象的状态之前将下一个对象传递给承诺:

   let people = [ 
                {groupId: 1, name: 'Jessica Coleman', status: 'Unknown', id:1}
                {groupId: 1, name: 'Eric Tomson', status: 'Unknown', id:2}
                {groupId: 1, name: 'Samuel Bell', status: 'Unknown', id:3}

      ];

现在我想绝对等待承诺在循环期间解决,即使承诺需要一分钟来计算这个实例。同一组的所有人都具有相同的地位。因此,promise 检查是否已经计算了一个组。如果是,则将其退回。否则,它会计算。这就是问题所在。杰西卡1还没说完,其他人就过去了。

    people.map(function(person) {
   // return the promise to array
   this.calculatorService
    .getStatus(person)
    .then(function(res) {
      person.status = res;


    });
});

【问题讨论】:

标签: javascript angular typescript


【解决方案1】:

mapforEach 这样的数组迭代器不适用于 Promise,因为它们不知道如何等待结果。改用简单的for 循环:

for (let person of people)
  person.status = await this.calculatorService.getStatus(person)

如果你真的想要一个“函数式”的方式(并且避免显式的 async/await),你可以定义一个类似于 bluebird 的 Promise.each 的函数:

Promise.each = function(ary, fn) {
    return ary.reduce((p, x) => p.then(() => fn(x)), Promise.resolve(null))
}

并像这样应用它:

function setStatus(person) {
    return calculatorService
        .getStatus(person)
        .then(res => person.status = res);
}

Promise.each(people, setStatus).then(...)

【讨论】:

  • 在这种情况下,async 会在哪里,因为 await 不能在非异步函数中工作?
  • @WedeAsmeraTseada 包含此循环构造的函数需要标记为async
【解决方案2】:

使其与async/await 同步工作。 (顺便说一句,for..of.map 更适合)。

for (let person of people) {
   person.status = await this.calculatorService.getStatus(person);
})

【讨论】:

  • 我建议您永远不要将.forEach 用于异步工作,因为在循环完成之前无法真正等待。 for...of 或简单的 for 循环更合适。
【解决方案3】:

你可以这样试试

let people = [ 
  {groupId: 1, name: 'Jessica Coleman', status: 'Unknown', id:1},
  {groupId: 1, name: 'Eric Tomson', status: 'Unknown', id:2},
  {groupId: 1, name: 'Samuel Bell', status: 'Unknown', id:3}
];


for (let person of people) {
  await this.calculatorService.getStatus(person).then(res => {
    person.status = res;
  });
}

【讨论】:

  • 您的Array.map 中没有返回任何内容;即使你这样做了,你最终也不能等待Array.map 完成异步工作。这也比它需要的复杂得多。你为什么将Promise 包装在另一个Promise 中?
  • 是的,它很复杂,但它按预期工作,我编辑了我的答案,现在我返回了一个更新的值。感谢您指出我的错误:)
  • 我在第一条评论中指出的所有错误仍然存​​在。您还使用 Array.map 作为循环。它并没有真正映射任何东西。
  • 您不需要将this.calculatorService.getStatus(person) 包装在另一个Promise 中。我会自己编辑您的答案,以便向您展示。
  • 这是一个使用模拟 getStatus 函数工作的示例:jsfiddle.net/ruegzowy
【解决方案4】:

你可以使用递归函数:

let people = [ 
    {groupId: 1, name: 'Jessica Coleman', status: 'Unknown', id:1},
    {groupId: 1, name: 'Eric Tomson', status: 'Unknown', id:2},
    {groupId: 1, name: 'Samuel Bell', status: 'Unknown', id:3}
];

function recCalculatorService(people) {
    if (!people || !people.length) {
        return;
    }
    this.calculatorService
        .getStatus(people.shift())
        .then(function(res) {
            person.status = res;
            recCalculatorService(people);
        });
}

// use people.slice() if you want to keep people array intact
recCalculatorService(people);

【讨论】:

    猜你喜欢
    • 2018-04-02
    • 2020-08-14
    • 1970-01-01
    • 2019-04-29
    • 2021-11-26
    • 2014-10-29
    • 2022-01-17
    • 2020-10-17
    • 2018-03-19
    相关资源
    最近更新 更多