design-patterns - 使用嵌套 promise 时如何避免意大利面条式代码?

标签 design-patterns promise

假设您有 6 个返回 Promise 的方法,A()、B()、C()、D()、E()、F() 和 G()。

在其他人正确执行之前,其中一些人无法正确执行。例如,C() 需要 A()。 F() 和 E() 需要 C()。 B() 需要 A() 和 F()。 G() 要求所有其他都完整。

A().then(() => {
  C().then(() => {
    F().then(() => {
      B();
    });
    E();
  });
}).then(() => {
  G();
});
D();

现在,假设需要在其中几个影响其行为的函数之间运行一些逻辑。

A().then(() => {
  let foop = this._service.getFoop();
  C(foop).then((noop) => {
    noop.forEach((n) => { n *= -1; });
    F(noop).then((boop) => {
      boop = boop.flatten();
      B(foop, boop);
    });
    E('MonkeyWrench');
  });
}).then(() => {
  let glipglop = this._service.findGlip(this.LOCAL_GLOP_KEY);
  G(glipglop, 42);
});
D();

然后,最重要的是,我们需要确保每个 Promise 都能捕获并处理错误。

A().then(() => {
  let foop = this._service.getFoop();
  C(foop).then((noop) => {
    noop.forEach((n) => { n *= -1; });
    F(noop).then((boop) => {
      boop = boop.flatten();
      B(foop, boop).catch((e) => {
        this.handleErrorB(e);
      });;
    }).catch((e) => {
      this.handleErrorF(e);
    });
    E('MonkeyWrench').catch((e) => {
      this.handleErrorE(e);
    });
  }).catch((e) => {
    this.handleErrorC(e);
  });
}).then(() => {
  let glipglop = _service.findGlip(this.LOCAL_GLOP_KEY);
  G(glipglop, 42);
}).catch((e) => {
  this.handleErrorA(e);
});
D().catch((e) => {
  this.handleErrorD(e);
});

现在我们有了一个由 Promise 组成的完整异步程序 - 它看起来一团糟。

有什么方法可以让这样的程序变得更容易阅读,以便 future 的贡献者可以避免 深入研究意大利面条代码?嵌套的 Promise 结构本质上是困惑的,还是有公认的协议(protocol) 清理它并使其更具可读性?

我读到http://www.datchley.name/promise-patterns-anti-patterns/它有一些好主意,例如使用promise.all([...]) 一次运行多个 Promise,但它不包含对嵌套 Promise 调用之间的逻辑的任何支持。

预先感谢任何愿意在这方面向我传授一些智慧的人。

最佳答案

Promise.all([…]) pattern在 Promise 调用之间的逻辑上工作特别 - 只需为新值创建一个新的 Promise!

var a = A();
var foop = a.then(() => this._service.getFoop());
var c = foop.then(C);
var noop = c.then(x => x.map(n => n * -1));
var f = noop.then(F);
var boop = f.then(x => x.flatten());
var b = Promise.all([boop, foop]).spread(B);
var e = Promise.all([boop, foop]).then(() => E('MonkeyWrench'));
var d = D();
var glipglop = Promise.all([d, e, f]).then(() =>
  this._service.findGlip(this.LOCAL_GLOP_KEY));
return Promise.all([gliplop, 42]).spread(G);

您可以将错误处理程序添加到相应的 Promise 中。

So now we have a complete async program made up of promises - and it looks like a complete mess.

这不是因为 promise ,而是因为您的控制流程一团糟。也许这是固有的复杂性,但很可能不是。尝试将部分逻辑分解为单独的函数 - 无可否认,这种策略更适合嵌套闭包模式。还要尽量避免副作用 - 需要在并发控制流中的特定时间运行并影响其他功能的逻辑总是很困惑。相反,应使其尽可能纯粹,仅处理沿流程传递的不可变值。

关于design-patterns - 使用嵌套 promise 时如何避免意大利面条式代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43577424/

相关文章:

c# - 在 MVP Winforms App 中共享模型

保存/加载其状态的 JavaScript 对象

javascript - 另一个 Promise.all 内的 Promise.all 似乎在完成之前退出,并显示未从 Promise 返回的警告

javascript - getUserMedia - 如果用户没有选择怎么办?

java - 过度依赖一个 arrayList

objective-c - 单例实例与类方法

java - 策略模式

javascript - webdriver.io 异步问题 - 单击一个元素,然后输入文本

javascript - 与 Bluebird 一起 Promising 已经基于 Promise 的库

javascript - 我可以在 Node 的 q Promise 中创建全局变量吗?