问题
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