JavaScript Promises
JavaScript Promises
O/p_ -
1. Collect things off the floor
2. Bin Trash
3. Begin messing things up again
• The code example shows the function cleanRoom
receiving an array of strings as the first argument and a
function as the second argument. The cleanRoom
function returns only after the done function returns.
});
});
});
});
O/P –
walk to the fish pond
Feed the fish
Match fish eat their food
Stand there and do nothing
• The example shows the logAfterDelay
function, which receives a string of “Walk to
the fish pond” as the first argument and a new
instance of the logAfterDelay function as the
second argument. As the number of nested
functions grows, the code becomes harder to
read.
• The programmer is faced with the challenge of
splitting code into separate functions to obey
the single responsibility principle and for
reusability, and balancing these items against
the readability of the code.
JavaScript: Learn Promises
Why do we need Promises?
// after 1 second signal that the job is done with the result "done"
setTimeout(() => resolve("done"), 1000);
});
• We can see two things by running the code above:
• The executor is called automatically and immediately (by
the new Promise).
• The executor receives two arguments: resolve and reject —
these functions are pre-defined by the JavaScript engine. So
we don’t need to create them. We only should call one of
them when ready.
• After one second of “processing” the executor
calls resolve("done") to produce the result:
• That was an example of a successful job completion, a
“fulfilled promise”.
• And now an example of the executor rejecting the promise
with an error:
let promise = new Promise(function(resolve, reject) {
// after 1 second signal that the job is finished with an error
setTimeout(() => reject(new Error("Whoops!")), 1000);
});
• Catch -
• If we’re interested only in errors, then we can use null as the first
argument: .then(null, errorHandlingFunction). Or we can
use .catch(errorHandlingFunction), which is exactly the same:-
• The call .catch(f) is a complete analog of .then(null, f), it’s just a shorthand.
• Finally -
• Just like there’s a finally clause in a regular try {...} catch {...},
there’s finally in promises.
• The call .finally(f) is similar to .then(f, f) in the sense that it
always runs when the promise is settled: be it resolve or reject.
• finally is a good handler for performing cleanup, e.g. stopping
our loading indicators, as they are not needed anymore, no
matter what the outcome is.
• Like this: -
new Promise((resolve, reject) => {
/* do something that takes time, and then call resolve/reject */
})
// runs when the promise is settled, doesn't matter successfully
or not
.finally(() => stop loading indicator)
.then(result => show result, err => show error)
Promises chaining
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
• The idea is that the result is passed through
the chain of .then handlers.
• Here the flow is:
• The initial promise resolves in 1 second (*),
• Then the .then handler is called (**).
• The value that it returns is passed to the
next .then handler (***)
• …and so on.
• As the result is passed along the chain of
handlers, we can see a sequence
of alert calls: 1 → 2 → 4.
• The whole thing works, because a call to promise.then returns a promise, so that we
can call the next .then on it.
• When a handler returns a value, it becomes the result of that promise, so the
next .then is called with it.
• To make these words more clear, here’s the start of the chain:
new Promise(function(resolve, reject) {
}).then(function(result) {
alert(result);
return result * 2; // <-- (1)
}) // <-- (2)
// .then…
• The value returned by .then is a promise, that’s why we are able to add
another .then at (2). When the value is returned in (1), that promise becomes
resolved, so the next handler runs with the value.
• A classic newbie error: technically we can also add many .then to a single promise.
This is not chaining.
• For example:
let promise = new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
promise.then(function(result) {
alert(result); // 1
return result * 2;
});
• What we did here is just several handlers to one promise.
They don’t pass the result to each other, instead they process
it independently.
• Here’s the picture (compare it with the chaining above):
• All .then on the same promise get the same result – the result
of that promise. So in the code above all alert show the
same: 1.
• In practice we rarely need multiple handlers for one promise.
Chaining is used much more often.
• Returning promises
• Normally, a value returned by a .then handler is immediately passed to the
next handler. But there’s an exception.
• If the returned value is a promise, then the further execution is suspended
until it settles. After that, the result of that promise is given to the
next .then handler.
• For instance:
new Promise(function(resolve, reject) {
}).then(function(result) {
alert(result); // 1
}).then(function(result) { // (**)
alert(result); // 2
}).then(function(result) {
alert(result); // 4
});
• Here the first .then shows 1 and returns new
Promise(…) in the line (*). After one second it
resolves, and the result (the argument
of resolve, here it’s result*2) is passed on to
handler of the second .then in the line (**). It
shows 2 and does the same thing.
• So the output is again 1 → 2 → 4, but now
with 1 second delay between alert calls.
• Returning promises allows us to build chains
of asynchronous actions.
Async/await
• The word “async” before a function means one simple thing: a function
always returns a promise. Even If a function actually returns a non-promise
value, prepending the function definition with the “async” keyword directs
JavaScript to automatically wrap that value in a resolved promise.
• For instance, the code above returns a resolved promise with
the result of 1, let’s test it:-
f().then(alert); // 1
• We could explicitly return a promise, that would be the same
as:-
f().then(alert); // 1
• So, async ensures that the function returns a
promise, and wraps non-promises in it. Simple
enough, right? But not only that. There’s another
keyword, await, that works only
inside async functions, and it’s pretty cool.
• Await -
• The syntax:-
// works only inside async functions
let value = await promise;
• The keyword await makes JavaScript wait until
that promise settles and returns its result.
• Here’s an example with a promise that resolves in
1 second:
async function f() {
alert(result); // "done!"
}
f();
• The function execution “pauses” at the
line (*) and resumes when the promise settles,
with result becoming its result. So the code
above shows “done!” in one second.
• Let’s emphasize: await literally makes
JavaScript wait until the promise settles, and
then go on with the result. That doesn’t cost
any CPU resources, because the engine can do
other jobs meanwhile: execute other scripts,
handle events etc.
• It’s just a more elegant syntax of getting the
promise result than promise.then, easier to
read and write.
• Can’t use await in regular functions
• If we try to use await in non-async function,
there would be a syntax error:
function f() {
let promise = Promise.resolve(1);
let result = await promise; // Syntax error
}