Removing Nested Promises

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:

  1. If you don't need the previous result then flatten out the promise chain like I did here
  2. 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



Leave a reply



Submit