Keeping Promise Chains Readable

て烟熏妆下的殇ゞ 提交于 2019-12-02 07:16:10

问题


I've grown used to promise chaining arrays. It's incredibly easy to read a promise chain when each promise is a line long such as

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

This is incredibly easy to read. However, when I create promise chains with custom functions, it gets much messier.

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 
  })

Now, this can be legible, but when the promise chain extends further, it gets to be a little much. If I make each promise it's own function, then I can streamline the process so the code looks something like this (which imo, is 1000x more legible).

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

This way, I can rearrange the functions without having to manipulate the values that get passed from one promise to the next. If a promise uses a result of another, it only needs to be after the other, but not immediately after. That way I can sneak promises in wherever I need.

However, this requires my promise chain to use variables outside each promise's scope. Is there a tried and true way to do this?

Edit - Seems async/await is the best way to do this, but I'm running Node on Heroku and it's not supported yet :/


回答1:


Well, you can use something like that with promises:

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

if you use my rsp module from npm.

Other than that you can use the async/await features of ES2017 to simplify the promises chains, especially their scope.

Because with code like this:

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

if you need to use the result of first query in the last thirdQueryAndStoreIt() handler, you have a problem with accessing the data that is out of scope. But when you do:

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);
}

then you don't have the problem with scope, as you can easily access all of the previously assigned variables.

See this for Node versions that support this syntax:

  • http://node.green/#ES2017-features-async-functions

You can use it with Node v7.6+ out of the box or with Node v7.0+ with the --harmony flag.

For older Node versions you can use co or Bluebird.coroutine for a similar syntax using generator functions and yield instead of await.




回答2:


if you really want, you can limit scope to a single meta-Promise by creating it yourself:

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

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

but the most legible way to do this is to use async/await.



来源:https://stackoverflow.com/questions/42765589/keeping-promise-chains-readable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!