Here we create a Promise object instead, often you get the final object from a function as return-value, so you don't have to think about how they are created, you often just have to call the then method on it and pass a callback.
Here we create one on our own, it takes a callback that receives two functions.
resolve has to be called when the asynchronous process finishes successfully.
reject has to be called when it fails.
As you may notice, this callback isn't the callback from the previous example. It's a wrapper to make a promise from a non-promise/callback function.
Anyway, promises bring you nice things:
You can call then as often as you like, the callbacks get all called when the promise succeeds.
The then method returns a new promise. The fetch function also returns a promise.
If we pass a callback to then that returns a promise itself, then will return this new promise.
In our example, the first then call returns what fetch returns, because fetch returns a promise.
The json method of our response object also returns a promise, so then will return that promise.
In the third then callback, we return a value from that parsed JSON, so thencreates a new promise for us that resolves to that value. This allows us to chain synchronous and asynchronous calls with then.
One little thing I'll add because I often see beginners get this wrong: (you wrote this but I still want to really emphasize this)
Don't have nested then blocks! then is a special function because it can return either a new promise or a concrete value. If you want to perform two promises sequentially, simple return the next promise from the then block.
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.
You know what a callback is, right?
Let's take the following example:
The
onTimeout
function takes acallback
which will be stored for later use. The later use is the timeout that triggers after 1 second.Problem here? When we call
onTimeout
too late, the timeout could be already have triggered, so we would add the callback, but nothing happens.Solution? Promises!
How do they work? Easy, they are monads :D
Joke aside...
They are objects you can attach your callbacks to.
Here we create a
Promise
object instead, often you get the final object from a function as return-value, so you don't have to think about how they are created, you often just have to call thethen
method on it and pass a callback.Here we create one on our own, it takes a callback that receives two functions.
resolve
has to be called when the asynchronous process finishes successfully.reject
has to be called when it fails.As you may notice, this callback isn't the callback from the previous example. It's a wrapper to make a promise from a non-promise/callback function.
Anyway, promises bring you nice things:
You can call
then
as often as you like, the callbacks get all called when the promise succeeds.You can call
then
whenever you like, the callbacks get called right away if the promise has succeeded in the past.You can chain promises with
then
to make asynchronous calls based on other asynchronous calls.The
then
method returns a new promise. Thefetch
function also returns a promise.If we pass a callback to
then
that returns a promise itself,then
will return this new promise.In our example, the first
then
call returns whatfetch
returns, becausefetch
returns a promise.The
json
method of ourresponse
object also returns a promise, sothen
will return that promise.In the third
then
callback, we return a value from that parsed JSON, sothen
creates a new promise for us that resolves to that value. This allows us to chain synchronous and asynchronous calls withthen
.So this example could be written a bit shorter:
I hope this helps, if you got any questions, ask away :)
Hey, thanks for explaining. This answer helps a lot.
How is this not a blogpost on itself :D
Men, thanks for the promises information.
One little thing I'll add because I often see beginners get this wrong: (you wrote this but I still want to really emphasize this)
Don't have nested then blocks!
then
is a special function because it can return either a new promise or a concrete value. If you want to perform two promises sequentially, simple return the next promise from the then block.Instead of
You can write
Which is much more readable. In functional terms,
then
is bothbind
andmap
, depending on the return value.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.