There is at least one good case in which it is defensible to nest .then, and that's when you want to some shared reference in both callbacks.
doAsyncThing().then(result1=>doMoreAsync(result1.path)).then(result2=>{/* wish I had access to result1 AND result2 here! */})
There are several solutions to sharing scope between earlier and later callbacks, including:
A) Create a mutable outer-scope let variable and assign it partway down the promise chain: this is probably the most intuitive solution, but does involve some (disciplined) mutation and pollution of the outer scope.
letresult1// undefineddoAsyncThing().then(result1arg=>{result1=result1arg// store in outer scopereturndoMoreAsync(result1.path)}).then(result2=>{console.log(result1,result2)})
B) Use a promise library with a feature that passes along state information in an implicit parameter, e.g. Bluebird and this (though that technically breaks the A+ spec); this is the least portable and most opaque way.
doAsyncThingViaBluebird().bind({})// this is Bluebird#bind, not Function#bind – misleading!.then(result1=>{this.result1=result1// store in implicit state objectreturndoMoreAsyncWithBluebird(result1.path)}).then(result2=>{console.log(this.result1,result2)})
C) use a nested promise chain, which introduces a little local callback indentation and verbosity but which does not pollute an outer scope or require any mutation:
doAsyncThing().then(result1=>{returndoMoreAsync(result1.path).then(result2=>{console.log(result1,result2)// have access to both params in scope})})
You can use this technique to pass both results down the chain by returning a container object such as an object or array:
doAsyncThing().then(result1=>{returndoMoreAsync(result1.path).then(result2=>[result1,result2])}).then(([result1,result2])=>{// using array destructuringconsole.log(result1,result2)})
The absolutely important thing however is to remember to return the internal promise chain, otherwise your next then will fire before the internal chain has actually settled.
doAsyncThing().then(result1=>{// INCORRECT OMISSION OF RETURN BELOW:doMoreAsync(result1.path).then(result2=>doStuffWith(result1,result2))}).then(()=>{// this callback fires prematurely!})
In practice, I more often use some outer-scope let binding over nested promise chains, but the latter are perfectly valid if done correctly.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
There is at least one good case in which it is defensible to nest
.then
, and that's when you want to some shared reference in both callbacks.There are several solutions to sharing scope between earlier and later callbacks, including:
A) Create a mutable outer-scope
let
variable and assign it partway down the promise chain: this is probably the most intuitive solution, but does involve some (disciplined) mutation and pollution of the outer scope.B) Use a promise library with a feature that passes along state information in an implicit parameter, e.g. Bluebird and
this
(though that technically breaks the A+ spec); this is the least portable and most opaque way.C) use a nested promise chain, which introduces a little local callback indentation and verbosity but which does not pollute an outer scope or require any mutation:
You can use this technique to pass both results down the chain by returning a container object such as an object or array:
The absolutely important thing however is to remember to
return
the internal promise chain, otherwise your nextthen
will fire before the internal chain has actually settled.In practice, I more often use some outer-scope
let
binding over nested promise chains, but the latter are perfectly valid if done correctly.