Removing nested promises
From every then
callback, you will need to return the new promise:
exports.viewFile = function(req, res) {
var fileId = req.params.id;
boxContentRequest('files/' + fileId + '/content', req.user.box.accessToken)
.then(function(response) {
return boxViewerRequest('documents', {url: response.request.href}, 'POST');
})
.then(function(response) {
return boxViewerRequest('sessions', {document_id: response.body.id}, 'POST');
})
.then(function(response) {
console.log(response);
});
};
The promise that is returned by the .then()
call will then resolve with the value from the "inner" promise, so that you easily can chain them.
Generic pattern:
somePromise.then(function(r1) {
return nextPromise.then(function(r2) {
return anyValue;
});
}) // resolves with anyValue
||
\||/
\/
somePromise.then(function(r1) {
return nextPromise;
}).then(function(r2) {
return anyValue;
}) // resolves with anyValue as well
javascript and promise: how to refactor/flatten the following nested promises?
Nesting promises is a known anti-pattern, you should chain them instead:
// the structure is vertical instead of a nested pyramid
return promise
.then(function helper0(instances) {
return helper1(instances, options)
})
.then(function helper2() {
return bluebird.delay(3000);
})
.then(function helper3() {
return helper4(localParams, options);
});
Returning a promise from the callback passed to then
adds that promise to the chain.
Using arrow functions would clean this up further:
return promise
.then(instances => helper1(instances, options))
.then(() => bluebird.delay(3000))
.then(() => helper4(localParams, options);
But note that using named functions would be a better approach for debugging purposes because of a more readable stack trace.
How do I flatten a nested promise dependency?
Instead of nesting callbacks, chain promises together with .then()
A note:
I'm not sure what Promise library you are using, but the idea is to return a rejected promise from the first .then() if there is an error, otherwise you return a successful promise. The promise library will then handle the error handling for you, going to the catch block if there is a rejected promise.
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);
});
edit:
The only issue is when you need to access both of the return values from the promises at the same time. When you flatten out a promise chain you lose access to the results from the previous promises.
You have a few options:
- If you don't need the previous result then flatten out the promise chain like I did here
If you do need the previous value
2a. And you don't care about the ordering of execution then use
Promise.all([promise1, promise2])
2b. And you do care about the ordering of the execution then you must use nested promises like you originally did.
How do I resolve nested promises in an object
If quote
and history
are promises it means that priceQuote
and makePriceHistoryRequest
are functions that return promises, in this case, you need to make the callback that iterates them async, not the wrapper:
function main() {
return Promise.all(symbols.map(async (symbol) => {
const record = {
[symbol]: {
quote: await priceQuote(token, symbol),
history: await makePriceHistoryRequest(token, symbol, slow * 2),
}
}
return record
})
}
main().then(value => console.log(value) )
Cannot get nested promises to return value to next promise chain
Sounds like a grouping mistake. Instead of
return o.distiller.new === true && !whiskey.distiller
? Distiller.newDistiller(o.distiller.value)
: Promise.resolve().then(…) // callback only called when no new distiller
you want
return (o.distiller.new && !whiskey.distiller
? Distiller.newDistiller(o.distiller.value)
: Promise.resolve()
).then(…) // callback always called
At least that is how did all the other conditionals :-)
I'm still grasping promise chaining
After having learned that you always need to return
from your asynchronous functions (which you did fine), you should have a look at how it is possible to flatten a chain (which applies to your code when all the conditionals are local expressions only, not early returns). Also I'd recommend not to indent chained method invocations as that quickly gets out of hand when nesting then
callbacks, but that's just my personal preference.
How to resolve nested promise in NodeJs?
as response.text() return promise
Using async/await
return fetch(url,config)
.then( async (response) => {
return {
"status" : response.status,
"payload": await response.text()
}
})
You can mix async/await
and .then
but it is not recommended because whats-wrong-with-awaiting-a-promise-chain
pure async/await
async function makeRequest (url,config) {
try{
const response= await fetch(url,config)
return{
"status" : response.status,
"payload": await response.text()
}
}
catch(error) {
console.log(error)
return {
"status": null,
"payload" : error.message
}
}
}
How can I wait for all dynamic nested promises to end?
Try using Promise.all
like this:
getContent() {
fetch(this.url)
.then((response) => response.text())
.then((data) => {
let jsonData = JSON.parse(data);
const promises = [];
for (let i=0; i<jsonData.results.length; i++) {
promises.push(this.fetchPokemon(jsonData.results[i].url));
}
return Promise.all(promises);
})
.then((results) => {
console.log(results);
})
.catch((error) => console.log(error));
}
So basically you just push all of the Promises to the array and then apply Promise.all
to wait for them to resolve.
How to structure nested Promises
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
Can you avoid nesting altogether with Promises?
Yes, you can always flatten a promise chain with Promise.all
(shorthand through Promise.join
in Bluebird) by using promises for the proxies they are. After all - promises abstract values, you can always unwrap a promise as late as you want and have other variables depend on it.
Whether or not it's more readable is another debate:
foo().then(function(a){
return bar(a).then(function(b){
return g(a,b); // "needed" to nest because I wanted `a`
});
});
Can be written as:
var a = foo();
var b = a.then(bar);
Promise.join(a, b, function(a,b){
return g(a, b); // alternatively, res could have been `Promise.join(a,b, g)`
});
So generally - you can always avoid nesting but a lot of time you might not want to.
In your case, this can even be:
function authenticate() {
var userPass = Promise.all([ getUsername().then(getUser), getPassword()]);
var passHash = userPass.get(0).get("passwordHash");
var newHash = userPass.get(1).then(hash);
var equal = Promise.join(userHash, newHash, function(a, b){ return a !==b });
return equal.then(function(val){ if(!val) throw new Error("..."); });
}
Flatter? Sure. Better? That's a whole other question. If you have a nested for
loop, you might want to keep it a nested for
loop and nest rather than hack around that option and use a single loop.
Related Topics
Parsing a String to a Date in JavaScript
Remove Duplicate Values from Js Array
What Characters Are Valid For JavaScript Variable Names
What Is the !! (Not Not) Operator in JavaScript
What's the Meaning of "=≫" (An Arrow Formed from Equals & Greater Than) in JavaScript
How to Attach Events to Dynamic HTML Elements With Jquery
What Is Event Bubbling and Capturing
Google Maps Js API V3 - Simple Multiple Marker Example
Use of 'Prototype' Vs. 'This' in JavaScript
Safely Turning a Json String into an Object
Methods in Es6 Objects: Using Arrow Functions
When Should I Use a Return Statement in Es6 Arrow Functions
Jquery Event Keypress: Which Key Was Pressed
How to Use the : (Conditional) Operator in JavaScript
How to Iterate Over a JavaScript Object