如何展平嵌套承诺依赖项

How do I flatten a nested promise dependency?

本文关键字:依赖 承诺 嵌套 何展平      更新时间:2023-09-26

我通过节点应用程序使用mondora/asteroid,通过承诺模式使用Meteor DDP。

有以下代码,我正在从回调样式重写为承诺样式,但卡在如何扁平化它上。

asteroid.call('Pony.search', { params })
  .then(res => {
    if (res.length === 1) {
      // something
      asteroid.call('Pony.finish', { params })
        // this part feels wrong
        .then(res => {
          // something else
        });
    } else {
      // nope
    }
  })
  .catch(err => {
    console.error(err);
  });

在第一个承诺响应中还有第二个asteroid.callthen,这是一个承诺。这部分感觉不对,好像它应该是平坦的而不是嵌套的,但我不确定如何到达那里。

编辑:

最终使用了这样的东西(仍然没有决定是否拥有第一个然后检查if length === 1并可能立即拒绝它。有谁知道这方面的最佳实践是什么?

asteroid.call('Pony.search', { params })
  .then(res => res.length === 1 ? res : Promise.reject())
  .then(res => asteroid.call('Pony.finish', { res[0].something }))
  .then(res => {
    // do something
  })
  .catch(err => {
    // handle the no found
    console.error(err);
  });

不是嵌套回调,而是将承诺与 .then() 一起链

注意:

我不确定您使用的是哪个 Promise 库,但这个想法是如果出现错误,则从第一个 .then() 返回被拒绝的承诺,否则返回成功的承诺。然后,promise 库将为您处理错误处理,如果有一个被拒绝的承诺,则转到 catch 块。

asteroid.call('Pony.search', { params })
  .then(res => {
    res.length === 1 ? return asteroid.call('Pony.finish', { params }) : Promise.reject();
  })
  .then(res => {
    //do stuff here
  })
  .catch(err => {
    console.error(err);
  });

编辑:

唯一的问题是当您需要同时访问承诺的两个返回值时。当您扁平化承诺链时,您将无法访问先前承诺的结果。

您有以下几种选择:

  1. 如果你不需要之前的结果,那么像我在这里所做的那样拉平承诺链
  2. 如果确实需要以前的值

    2一.而且您不关心执行顺序,然后使用Promise.all([promise1, promise2])

    2b.而且你确实关心执行的顺序,那么你必须像你最初一样使用嵌套的承诺。

如果承诺是嵌套的,则承诺和回调之间没有区别。

尝试更改代码以使用承诺链:

asteroid.call('Pony.search', { params })
  .then(res => {
    if (res.length === 1) {
      // something
      let p1 = asteroid.call('Pony.finish', { params });
      return p1;
    }
    else {
      // nope
    }
  })
  .then (function SomeThingElse(res2){
    // something else
    // res2 is return value from nested asteroid.call
  })
  .catch(err => {
    console.error(err);
  });

由于第一个解析处理程序返回一个 Promise p1,链中下一个函数 (function SomeThingElse) 的调用被推迟到p1 resolved

现在扩展此示例:

asteroid.call('Pony.search', { params })
  .then(res => {
    if (res.length === 1) {
      // something
      let p1 = asteroid.call('Pony.finish', { params });
      return p1;
    }
    else {
      // nope
    }
  })
  .then (function SomeThingElse(res2){
    // something else
    // res2 is return value from nested asteroid.call
  })
  .then (function AnotherFunc(res3){
  })
  .catch(err => {
    console.error(err);
  });

如果SomeThingElse返回一个Promise,则AnotherFunc的调用将延迟到该承诺被解决。

如果SomeThingElse没有返回PromiseAnotherFunc将立即被调用,参数与收到的参数相同。换句话说,解析 p1 时会同时调用 SomeThingElseAnotherFunc