Tuesday, 14 May 2019

What is promise in javascript?

As explained beautifully by Ilya Kantor in detail on https://javascript.info/promise-basics
The core idea behind promises is that a promise represents the result of an asynchronous operation. A promise is in one of three different states:
  • pending - The initial state of a promise.
  • fulfilled - The state of a promise representing a successful operation.
  • rejected - The state of a promise representing a failed operation.
Once a promise is fulfilled or rejected, it is immutable (i.e. it can never change again).
The constructor syntax for a promise object is:
let promise = new Promise(function(resolve, reject) {
  // executor (the producing code, "singer")
});
The function passed to new Promise is called the executor. When the promise is created, this executor function runs automatically. It contains the producing code, that should eventually produce a result.
The resulting promise object has internal properties:
  • state — initially “pending”, then changes to either “fulfilled” or “rejected”,
  • result — an arbitrary value of your choosing, initially undefined.
When the executor finishes the job, it should call one of the functions that it gets as arguments:
  • resolve(value) — to indicate that the job finished successfully:
    • sets state to "fulfilled",
    • sets result to value.
  • reject(error) — to indicate that an error occurred:
    • sets state to "rejected",
    • sets result to error.
To summarize, the executor should do a job (something that takes time usually) and then call resolve or reject to change the state of the corresponding Promise object.
The Promise that is either resolved or rejected is called “settled”, as opposed to a “pending” Promise.

Consumers: then, catch, finally

A Promise object serves as a link between the executor (the “producing code” or “singer”) and the consuming functions (the “fans”), which will receive the result or error. Consuming functions can be registered (subscribed) using methods .then.catch and .finally.

then

The most important, fundamental one is .then.
The syntax is:


                                         
                                                     promise.then(
  function(result) { /* handle a successful result */ },
  function(error) { /* handle an error */ }
);
The first argument of .then is a function that:
  1. runs when the Promise is resolved, and
  2. receives the result.
The second argument of .then is a function that:
  1. runs when the Promise is rejected, and
  2. receives the error.
For instance, here’s a reaction to a successfully resolved promise:







let promise = new Promise(function(resolve, reject) {
  setTimeout(() => resolve("done!"), 1000);
});

// resolve runs the first function in .then
promise.then(
  result => alert(result), // shows "done!" after 1 second
  error => alert(error) // doesn't run
);
The first function was executed.
And in the case of a rejection – the second one:
let promise = new Promise(function(resolve, reject) {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// reject runs the second function in .then
promise.then(
  result => alert(result), // doesn't run
  error => alert(error) // shows "Error: Whoops!" after 1 second
);

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:






let promise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("Whoops!")), 1000);
});

// .catch(f) is the same as promise.then(null, f)
promise.catch(alert); // shows "Error: Whoops!" after 1 second
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 any more, 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)
It’s not exactly an alias though. There are several important differences:
  1. finally handler has no arguments. In finally we don’t know whether the promise is successful or not. That’s all right, as our task is usually to perform “general” finalizing procedures.
  2. Finally passes through results and errors to the next handler.
    For instance, here the result is passed through finally to then:
    new Promise((resolve, reject) => {
      setTimeout(() => resolve("result"), 2000)
    })
      .finally(() => alert("Promise ready"))
      .then(result => alert(result)); // <-- .then handles the result
    And here there’s an error in the promise, passed through finally to catch:
    new Promise((resolve, reject) => {
      throw new Error("error");
    })
      .finally(() => alert("Promise ready"))
      .catch(err => alert(err));  // <-- .catch handles the error object


Promise API




There are 4 static methods in the Promise class. We’ll quickly cover their use cases here.

Promise.resolve

The syntax:
let promise = Promise.resolve(value);
Returns a resolved promise with the given value.

Promise.reject

The syntax:
let promise = Promise.reject(error);
Create a rejected promise with the error.

Promise.all

Let’s say we want to run many promises to execute in parallel, and wait till all of them are ready.
For instance, download several URLs in parallel and process the content when all are done.
That’s what Promise.all is for.
The syntax is:
let promise = Promise.all([...promises...]);
It takes an array of promises (technically can be any iterable, but usually an array) and returns a new promise.
The new promise resolves when all listed promises are settled and has an array of their results.
For instance, the Promise.all below settles after 3 seconds, and then its result is an array [1, 2, 3]:
Promise.all([
  new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
  new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
  new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then(alert); // 1,2,3 when promises are ready: each promise contributes an array member
Please note that the relative order is the same. Even though the first promise takes the longest time to resolve, it is still first in the array of results.
A common trick is to map an array of job data into an array of promises, and then wrap that into Promise.all.
For instance, if we have an array of URLs, we can fetch them all like this:
let urls = [
  'https://api.github.com/users/iliakan',
  'https://api.github.com/users/remy',
  'https://api.github.com/users/jeresig'
];

// map every url to the promise fetch(github url)
let requests = urls.map(url => fetch(url));

// Promise.all waits until all jobs are resolved
Promise.all(requests)
  .then(responses => responses.forEach(
    response => alert(`${response.url}: ${response.status}`)
  ));

Promise.race

Similar to Promise.all, it takes an iterable of promises, but instead of waiting for all of them to finish, it waits for the first result (or error), and goes on with it.
The syntax is:
let promise = Promise.race(iterable);
For instance, here the result will be 1:
Promise.race([
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then(alert); // 1

Summary

There are 4 static methods of Promise class:
  1. Promise.resolve(value) – makes a resolved promise with the given value.
  2. Promise.reject(error) – makes a rejected promise with the given error.
  3. Promise.all(promises) – waits for all promises to resolve and returns an array of their results. If any of the given promises rejects, then it becomes the error of Promise.all, and all other results are ignored.
  4. Promise.race(promises) – waits for the first promise to settle, and its result/error becomes the outcome.