【问题标题】:Keeping Promise Chains Readable保持 Promise Chains 的可读性
【发布时间】:2017-03-13 14:04:30
【问题描述】:

我已经习惯于承诺链式数组。当每个承诺都是一行时,阅读承诺链非常容易,例如

myArray.map(x => convertX)
  .filter()
  .whatever()
  .etc()

这非常容易阅读。但是,当我使用自定义函数创建承诺链时,它变得更加混乱。

database.query(first query)
  .then(results => {
    // do stuff
    // do more
    // even more
    return database.query(second query)
  })
  .then(results => {
    // rinse and repeat
  })
  .catch(err => { 
    // error handling 
  })

现在,这可能是清晰的,但是当 Promise 链进一步扩展时,它会变得有点多。如果我让每个承诺都有自己的功能,那么我可以简化流程,使代码看起来像这样(imo,它的可读性提高了 1000 倍)。

db.query(first query)
  .then(storeFirstQuery)
  .then(secondQueryAndStoreIt)
  .then(thirdQueryAndStoreIt)
  .catch(errHandlingFunction)

这样,我可以重新排列函数,而无需操作从一个 Promise 传递到下一个 Promise 的值。如果一个 Promise 使用另一个的结果,它只需要在另一个之后,而不是紧随其后。这样我就可以在任何需要的地方偷偷做出承诺。

但是,这需要我的 Promise 链使用每个 Promise 范围之外的变量。有没有一种行之有效的方法来做到这一点?

编辑 - 似乎 async/await 是最好的方法,但我在 Heroku 上运行 Node 并且它还不支持:/

【问题讨论】:

  • 您不是第一个似乎喜欢您选择的方法的人。我不知道,因为它是易读的英语,而不是易读的 JavaScript。这是"callback lite"

标签: javascript node.js es6-promise


【解决方案1】:

好吧,你可以在 promise 中使用类似的东西:

myArray.map(x => convertX)
  .filter()
  .whatever()
  .etc()

如果你使用我的来自 npm 的 rsp 模块。

除此之外,您还可以使用 ES2017 的 async/await 功能来简化 Promise 链,尤其是它们的范围。

因为有这样的代码:

db.query(first query)
  .then(storeFirstQuery)
  .then(secondQueryAndStoreIt)
  .then(thirdQueryAndStoreIt)
  .catch(errHandlingFunction)

如果您需要在最后一个 thirdQueryAndStoreIt() 处理程序中使用第一个查询的结果,那么您在访问超出范围的数据时会遇到问题。但是当你这样做时:

try {
    let a = await db.query(first query);
    let b = await storeFirstQuery();
    let c = await secondQueryAndStoreIt();
    let d = await thirdQueryAndStoreIt(a); // use 'a' here
} catch (e) {
    errHandlingFunction(e);
}

那么您就没有作用域的问题,因为您可以轻松访问所有先前分配的变量。

查看支持此语法的 Node 版本:

您可以将其与 Node v7.6+ 一起使用,也可以与 Node v7.0+ 一起使用,并带有 --harmony 标志。

对于较旧的 Node 版本,您可以使用 coBluebird.coroutine 使用生成器函数和yield 而不是 await 的类似语法。

【讨论】:

  • 是的,async/await 似乎是最好的方法。不幸的是,我在 Heroku 上运行 Node,但它还不支持。
  • 你可以在没有 async/await 的情况下做同样的事情。这只是养眼。
【解决方案2】:

如果你真的想要,你可以通过自己创建一个元 Promise 来限制范围:

return new Promise((resolve, reject) => {
  const f1 = () => { /* ... */ };
  const f2 = () => { /* ... */ };
  const f3 = () => { /* ... */ };

  return db.query()
    .then(f1)
    .then(f2)
    .then(f3)
    .then(resolve)
    .catch(reject);
});

但最清晰的方法是使用async/await

【讨论】:

  • 我应该补充一点,我在 Heroku 上运行的 Node 服务器上执行所有这些操作。他们还不支持async/await :/
  • @matt 嗯?此答案中没有 async/await。
  • @Dan 不要做出“元承诺”。只需使用常规函数 (IIFE) 来创建闭包并从中返回原始承诺链。
  • @Tomalak “但最清晰的方法是使用 async/await”
  • 当然,但答案中的代码是相关的。在这种情况下,对于没有它的环境,它相当于 async/await 版本。
猜你喜欢
  • 2015-09-30
  • 2020-05-17
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
  • 1970-01-01
  • 2016-06-27
相关资源
最近更新 更多