Promise reject throw error

This article covers the use of reject and throw premises in Javascript and explains it s differences.reject It is an inbuilt function in Javascript that returns a Promise object which has been rejected for a particular given reason. Syntax Promise.reject reason Examples The reason can be a simple string message or you

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    This article covers the use of reject and throw premises in Javascript and explains it’s differences.
    reject(): It is an inbuilt function in Javascript that returns a Promise object which has been rejected for a particular given reason.
     

    Syntax:  

    Promise.reject(reason)

    Examples: The reason can be a simple string message or you can even pass an Error object.  

    • Program 1: Passing a string message as the reason.

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

       reject( 'promise failed!' );

    });

    p.catch(err => {

        console.log( err );

    });

    </script>

    • Output: 
       
    promise failed!
    • Program 2: Passing an instanceOf Error as reason.

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

       reject( new Error( 'promise failed!' ) );

    });

    p.catch( err => {

        console.log( err );

    });

    </script>

    • Output: As you can see when we are passing an Error object we get the entire Error tree. So it is upto the user which one the user prefers.
    Error: promise failed!
        at :4:9
        at new Promise ()
        at :2:11
        at render (tryit.php:202)
        at tryit.php:170
        at dispatch (jquery.js:4435)
        at r.handle (jquery.js:4121)

    throw: It is used in JavaScript to create and throw user defined exceptions. Using JavaScript throw statement, you can completely control program flow and generate the user define error messages. If we use throw instead of reject() in the above two examples the results will be exactly same (you can try it yourself just by replacing reject with throw).
    Examples: However throw can be used in any Javascript try-catch block and not only with promises. 

    • Program 1: Using throw in a promise.

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

       throw( 'promise failed!' );

    });

    p.catch(err => {

        console.log( err );

    });

    </script>

    • Output:
    promise failed!
    • Program 2: Using throw without a promise.

    javascript

    <script>

    var a = 20;

    try

    {

      if( a < 25 )

        throw ( 'Less than 25' );

      console.log( 'Okay!' );

    }

    catch(err)

    {

      console.log( err );

    }

    </script>

    • Output: Now as we have understood the basic working of both reject and throw, let us talk about the differences between them:
    Less than 25

    Comparison between Promise- reject and throw:
    1. If there is an asynchronous callback function inside the Promise then we cannot use throw from inside the callback function as it will not be recognised by catch() and we will be getting an error in the output.  

    • Program 1:

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

        setTimeout( () => { 

          throw( 'promise failed!' );

        }, 1000);

      });

      p.catch( ( err )=> {

        console.log( err );

      });

    </script>

    • Output: As you can see the error message (“promise failed!”) has been printed in the output but it wasn’t printed by the catch() function of our promise. It becomes an uncaught exception.
    /home/akarshan/Desktop/Projects/Personal/gfg/app.js:3
          throw( 'promise failed!' );
          ^
    promise failed!
    (Use `node --trace-uncaught ...` to show where the exception was thrown)
    • Program 2: To resolve the above situation we can make use of reject() method.

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

        setTimeout( () => {

          reject( 'promise failed!' );

        }, 1000);

      });

      p.catch( (err) => {

        console.log( err );

      });

    </script>

    • Output: Here the catch block is able to recognise reject() and print the corresponding message.
    promise failed!

    2. This is a very basic difference. If throw is encountered anywhere inside a function the exception is thrown immediately and the control flow is terminated.In other words after throwing the exception control comes out of the function inside which the exception was thrown.  

    • Program 1:

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

          throw( 'promise failed!' );     

          console.log("Here");

      });

    p.catch( err => {

        console.log( err )

    });

    </script>

    • Output: From this example it is clear that the statement console.log(“Here”) is not getting executed. 
       
    'promise failed!'
    • Program 2: To resolve above situation we use reject() instead of throw the statements after the reject statement inside the function will get executed before the control goes to the catch block. 
       

    javascript

    <script>

    const p = new Promise( ( resolve, reject ) => {

          reject( 'promise failed!' );     

          console.log( "Here" );

      });

    p.catch( err => {

        console.log( err )

    });

    </script>

    • Output:
    Here
    promise failed!

    3. The reject can only be used with a Javascript promise but throw unlike reject can be used to create and throw user-defined exceptions in any try-catch block and not only the ones with promises. If you use Promise.reject() in a try-catch block which is not associated with a promise, UnhandledPromiseRejectionWarning error will pop up.  

    • Program 1:

    javascript

    <script>

    var a=20;

    try{

    if( a < 25 )

       Promise.reject ( 'Less than 25' );

    console.log( 'Okay!' );

    }

    catch(err)

    {

      console.log( "inside catch" );

      console.log( err );

    }

    </script>

    • Output: Here, UnhandledPromiseRejectionWarning error comes as Promise.reject() cannot find a catch block associated with a Promise object.
    Okay!
    • Program 2: The catch block in the above code is not associated with any Promise object and so it is not executed. This is clear from the output as the message “inside catch” is not getting printed. But if we use throw this error will not occur.

    javascript

    <script>

    var a=20;

    try{

    if( a < 25 )

      throw ( 'Less than 25' );

    console.log( 'Okay!' );

    }

    catch(err)

    {

      console.log( "inside catch" );

      console.log( err );

    }

    </script>

    • Output:
    inside catch
    Less than 25

    JavaScript Promise Tutorial – How to Resolve or Reject Promises in JS

    Promises are important building blocks for asynchronous operations in JavaScript. You may think that promises are not so easy to understand, learn, and work with. And trust me, you are not alone!

    Promises are challenging for many web developers, even after spending years working with them.

    In this article, I want to try to change that perception while sharing what I’ve learned about JavaScript Promises over the last few years. Hope you find it useful.

    What is a Promise in JavaScript?

    A Promise is a special JavaScript object. It produces a value after an asynchronous (aka, async) operation completes successfully, or an error if it does not complete successfully due to time out, network error, and so on.

    Successful call completions are indicated by the resolve function call, and errors are indicated by the reject function call.

    You can create a promise using the promise constructor like this:

    let promise = new Promise(function(resolve, reject) {    
        // Make an asynchronous call and either resolve or reject
    });

    In most cases, a promise may be used for an asynchronous operation. However, technically, you can resolve/reject on both synchronous and asynchronous operations.

    Hang on, don’t we have callback functions for async operations?

    Oh, yes! That’s right. We have callback functions in JavaScript. But, a callback is not a special thing in JavaScript. It is a regular function that produces results after an asynchronous call completes (with success/error).

    The word ‘asynchronous’ means that something happens in the future, not right now. Usually, callbacks are only used when doing things like network calls, or uploading/downloading things, talking to databases, and so on.

    While callbacks are helpful, there is a huge downside to them as well. At times, we may have one callback inside another callback that’s in yet another callback and so on. I’m serious! Let’s understand this «callback hell» with an example.

    How to Avoid Callback Hell – PizzaHub Example

    Let’s order a Veg Margherita pizza 🍕 from the PizzaHub. When we place the order, PizzaHub automatically detects our location, finds a nearby pizza restaurant, and finds if the pizza we are asking for is available.

    If it’s available, it detects what kind of beverages we get for free along with the pizza, and finally, it places the order.

    If the order is placed successfully, we get a message with a confirmation.

    So how do we code this using callback functions? I came up with something like this:

    function orderPizza(type, name) {
        
        // Query the pizzahub for a store
        query(`/api/pizzahub/`, function(result, error){
           if (!error) {
               let shopId = result.shopId;
               
               // Get the store and query pizzas
               query(`/api/pizzahub/pizza/${shopid}`, function(result, error){
                   if (!error) {
                       let pizzas = result.pizzas;
                       
                       // Find if my pizza is availavle
                       let myPizza = pizzas.find((pizza) => {
                           return (pizza.type===type && pizza.name===name);
                       });
                       
                       // Check for the free beverages
                       query(`/api/pizzahub/beverages/${myPizza.id}`, function(result, error){
                           if (!error) {
                               let beverage = result.id;
                               
                               // Prepare an order
                               query(`/api/order`, {'type': type, 'name': name, 'beverage': beverage}, function(result, error){
                                  if (!error) {
                                      console.log(`Your order of ${type} ${name} with ${beverage} has been placed`);
                                  } else {
                                      console.log(`Bad luck, No Pizza for you today!`);
                                  }
                               });
    
                           }
                       })
                   }
               });
           } 
        });
    }
    
    // Call the orderPizza method
    orderPizza('veg', 'margherita');

    Let’s have a close look at the orderPizza function in the above code.

    It calls an API to get your nearby pizza shop’s id. After that, it gets the list of pizzas available in that restaurant. It checks if the pizza we are asking for is found and makes another API call to find the beverages for that pizza. Finally the order API places the order.

    Here we use a callback for each of the API calls. This leads us to use another callback inside the previous, and so on.

    This means we get into something we call (very expressively) Callback Hell. And who wants that? It also forms a code pyramid which is not only confusing but also error-prone.

    callback-hell

    Demonstration of callback hell and pyramid

    There are a few ways to come out of (or not get into) callback hell. The most common one is by using a Promise or async function. However, to understand async functions well, you need to have a fair understanding of Promises first.

    So let’s get started and dive into promises.

    Understanding Promise States

    Just to review, a promise can be created with the constructor syntax, like this:

    let promise = new Promise(function(resolve, reject) {
      // Code to execute
    });

    The constructor function takes a function as an argument. This function is called the executor function.

    // Executor function passed to the 
    // Promise constructor as an argument
    function(resolve, reject) {
        // Your logic goes here...
    }

    The executor function takes two arguments, resolve and reject. These are the callbacks provided by the JavaScript language. Your logic goes inside the executor function that runs automatically when a new Promise is created.

    For the promise to be effective, the executor function should call either of the callback functions, resolve or reject. We will learn more about this in detail in a while.

    The new Promise() constructor returns a promise object. As the executor function needs to handle async operations, the returned promise object should be capable of informing when the execution has been started, completed (resolved) or retuned with error (rejected).

    A promise object has the following internal properties:

    1. state – This property can have the following values:
    • pending: Initially when the executor function starts the execution.
    • fulfilled: When the promise is resolved.
    • rejected: When the promise is rejected.

    states_1

    Promise states

    2.  result – This property can have the following values:

    • undefined: Initially when the state value is pending.
    • value: When resolve(value) is called.
    • error: When reject(error) is called.

    These internal properties are code-inaccessible but they are inspectable. This means that we will be able to inspect the state and result property values using the debugger tool, but we will not be able to access them directly using the program.

    promise_state_inspect

    Able to inspect the internal properties of a promise

    A promise’s state can be pending, fulfilled or rejected. A promise that is either resolved or rejected is called settled.

    states_2

    A settled promise is either fulfilled or rejected

    How promises are resolved and rejected

    Here is an example of a promise that will be resolved (fulfilled state) with the value I am done immediately.

    let promise = new Promise(function(resolve, reject) {
        resolve("I am done");
    });

    The promise below will be rejected (rejected state) with the error message Something is not right!.

    let promise = new Promise(function(resolve, reject) {
        reject(new Error('Something is not right!'));
    });

    An important point to note:

    A Promise executor should call only one resolve or one reject. Once one state is changed (pending => fulfilled or pending => rejected), that’s all. Any further calls to resolve or reject will be ignored.

    let promise = new Promise(function(resolve, reject) {
      resolve("I am surely going to get resolved!");
    
      reject(new Error('Will this be ignored?')); // ignored
      resolve("Ignored?"); // ignored
    });

    In the example above, only the first one to resolve will be called and the rest will be ignored.

    How to handle a Promise once you’ve created it

    A Promise uses an executor function to complete a task (mostly asynchronously). A consumer function (that uses an outcome of the promise) should get notified when the executor function is done with either resolving (success) or rejecting (error).

    The handler methods, .then(), .catch() and .finally(), help to create the link between the executor and the consumer functions so that they can be in sync when a promise resolves or rejects.

    consumer_executor

    The executor and consumer functions

    How to Use the .then() Promise Handler

    The .then() method should be called on the promise object to handle a result (resolve) or an error (reject).

    It accepts two functions as parameters. Usually, the .then() method should be called from the consumer function where you would like to know the outcome of a promise’s execution.

    promise.then(
      (result) => { 
         console.log(result);
      },
      (error) => { 
         console.log(error);
      }
    );

    If you are interested only in successful outcomes, you can just pass one argument to it, like this:

    promise.then(
      (result) => { 
          console.log(result);
      }
    );

    If you are interested only in the error outcome, you can pass null for the first argument, like this:

    promise.then(
      null,
      (error) => { 
          console.log(error)
      }
    );

    However, you can handle errors in a better way using the .catch() method that we will see in a minute.

    Let’s look at a couple of examples of handling results and errors using the .then and .catch handlers. We will make this learning a bit more fun with a few real asynchronous requests. We will use the PokeAPI to get information about Pokémon and resolve/reject them using Promises.

    First, let us create a generic function that accepts a PokeAPI URL as argument and returns a Promise. If the API call is successful, a resolved promise is returned. A rejected promise is returned for any kind of errors.

    We will be using this function in several examples from now on to get a promise and work on it.

    function getPromise(URL) {
      let promise = new Promise(function (resolve, reject) {
        let req = new XMLHttpRequest();
        req.open("GET", URL);
        req.onload = function () {
          if (req.status == 200) {
            resolve(req.response);
          } else {
            reject("There is an Error!");
          }
        };
        req.send();
      });
      return promise;
    }
    Utility method to get a Promise

    Example 1: Get 50 Pokémon’s information:

    const ALL_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon?limit=50';
    
    // We have discussed this function already!
    let promise = getPromise(ALL_POKEMONS_URL);
    
    const consumer = () => {
        promise.then(
            (result) => {
                console.log({result}); // Log the result of 50 Pokemons
            },
            (error) => {
                // As the URL is a valid one, this will not be called.
                console.log('We have encountered an Error!'); // Log an error
        });
    }
    
    consumer();

    Example 2: Let’s try an invalid URL

    const POKEMONS_BAD_URL = 'https://pokeapi.co/api/v2/pokemon-bad/';
    
    // This will reject as the URL is 404
    let promise = getPromise(POKEMONS_BAD_URL);
    
    const consumer = () => {
        promise.then(
            (result) => {
                // The promise didn't resolve. Hence, it will
                // not be executed.
                console.log({result});
            },
            (error) => {
                // A rejected prmise will execute this
                console.log('We have encountered an Error!'); // Log an error
            }
        );
    }
    
    consumer();

    How to Use the .catch() Promise Handler

    You can use this handler method to handle errors (rejections) from promises. The syntax of passing null as the first argument to the .then() is not a great way to handle errors. So we have .catch() to do the same job with some neat syntax:

    // This will reject as the URL is 404
    let promise = getPromise(POKEMONS_BAD_URL);
    
    const consumer = () => {
        promise.catch(error => console.log(error));
    }
    
    consumer();

    If we throw an Error like new Error("Something wrong!")  instead of calling the reject from the promise executor and handlers, it will still be treated as a rejection. It means that this will be caught by the .catch handler method.

    This is the same for any synchronous exceptions that happen in the promise executor and handler functions.

    Here is an example where it will be treated like a reject and the .catch handler method will be called:

    new Promise((resolve, reject) => {
      throw new Error("Something is wrong!");// No reject call
    }).catch((error) => console.log(error)); 

    How to Use the .finally() Promise Handler

    The .finally() handler performs cleanups like stopping a loader, closing a live connection, and so on. The finally() method will be called irrespective of whether a promise resolves or rejects. It passes through the result or error to the next handler which can call a .then() or .catch() again.

    Here is an example that’ll help you understand all three methods together:

    let loading = true;
    loading && console.log('Loading...');
    
    // Gatting Promise
    promise = getPromise(ALL_POKEMONS_URL);
    
    promise.finally(() => {
        loading = false;
        console.log(`Promise Settled and loading is ${loading}`);
    }).then((result) => {
        console.log({result});
    }).catch((error) => {
        console.log(error)
    });

    To explain a bit further:

    • The .finally() method makes loading false.
    • If the promise resolves, the .then() method will be called. If the promise rejects with an error, the .catch() method will be called. The .finally() will be called irrespective of the resolve or reject.

    What is the Promise Chain?

    The  promise.then() call always returns a promise. This promise will have the state as pending and result as undefined. It allows us to call the next .then method on the new promise.

    When the first .then method returns a value, the next .then method can receive that. The second one can now pass to the third .then() and so on. This forms a chain of .then methods to pass the promises down. This phenomenon is called the Promise Chain.

    image-105

    Promise Chain

    Here is an example:

    let promise = getPromise(ALL_POKEMONS_URL);
    
    promise.then(result => {
        let onePokemon = JSON.parse(result).results[0].url;
        return onePokemon;
    }).then(onePokemonURL => {
        console.log(onePokemonURL);
    }).catch(error => {
        console.log('In the catch', error);
    });

    Here we first get a promise resolved and then extract the URL to reach the first Pokémon. We then return that value and it will be passed as a promise to the next .then() handler function. Hence the output,

    https://pokeapi.co/api/v2/pokemon/1/

    The .then method can return either:

    • A value (we have seen this already)
    • A brand new promise.

    It can also throw an error.

    Here is an example where we have created a promise chain with the .then methods which returns results and a new promise:

    // Promise Chain with multiple then and catch
    let promise = getPromise(ALL_POKEMONS_URL);
    
    promise.then(result => {
        let onePokemon = JSON.parse(result).results[0].url;
        return onePokemon;
    }).then(onePokemonURL => {
        console.log(onePokemonURL);
        return getPromise(onePokemonURL);
    }).then(pokemon => {
        console.log(JSON.parse(pokemon));
    }).catch(error => {
        console.log('In the catch', error);
    });

    In the first .then call we extract the URL and return it as a value. This URL will be passed to the second .then call where we are returning a new promise taking that URL as an argument.

    This promise will be resolved and passed down to the chain where we get the information about the Pokémon. Here is the output:

    image-159

    Output of the promise chain call

    In case there is an error or a promise rejection, the .catch method in the chain will be called.

    A point to note: Calling .then multiple times doesn’t form a Promise chain. You may end up doing something like this only to introduce a bug in the code:

    let promise = getPromise(ALL_POKEMONS_URL);
    
    promise.then(result => {
        let onePokemon = JSON.parse(result).results[0].url;
        return onePokemon;
    });
    promise.then(onePokemonURL => {
        console.log(onePokemonURL);
        return getPromise(onePokemonURL);
    });
    promise.then(pokemon => {
        console.log(JSON.parse(pokemon));
    });
    

    We call the .then method three times on the same promise, but we don’t pass the promise down. This is different than the promise chain. In the above example, the output will be an error.

    image-160

    How to Handle Multiple Promises

    Apart from the handler methods (.then, .catch, and .finally), there are six static methods available in the Promise API. The first four methods accept an array of promises and run them in parallel.

    1. Promise.all
    2. Promise.any
    3. Promise.allSettled
    4. Promise.race
    5. Promise.resolve
    6. Promise.reject

    Let’s go through each one.

    The Promise.all() method

    Promise.all([promises]) accepts a collection (for example, an array) of promises as an argument and executes them in parallel.

    This method waits for all the promises to resolve and returns the array of promise results. If any of the promises reject or execute to fail due to an error, all other promise results will be ignored.

    Let’s create three promises to get information about three Pokémons.

    const BULBASAUR_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/bulbasaur';
    const RATICATE_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/raticate';
    const KAKUNA_POKEMONS_URL = 'https://pokeapi.co/api/v2/pokemon/kakuna';
    
    
    let promise_1 = getPromise(BULBASAUR_POKEMONS_URL);
    let promise_2 = getPromise(RATICATE_POKEMONS_URL);
    let promise_3 = getPromise(KAKUNA_POKEMONS_URL);

    Use the Promise.all() method by passing an array of promises.

    Promise.all([promise_1, promise_2, promise_3]).then(result => {
        console.log({result});
    }).catch(error => {
        console.log('An Error Occured');
    });

    Output:

    image-161

    As you see in the output, the result of all the promises is returned. The time to execute all the promises is equal to the max time the promise takes to run.

    The Promise.any() method

    Promise.any([promises]) — Similar to the all() method, .any() also accepts an array of promises to execute them in parallel. This method doesn’t wait for all the promises to resolve. It is done when any one of the promises is settled.

     Promise.any([promise_1, promise_2, promise_3]).then(result => {
         console.log(JSON.parse(result));
     }).catch(error => {
         console.log('An Error Occured');
     });

    The output would be the result of any of the resolved promises:

    image-162

    The Promise.allSettled() method

    romise.allSettled([promises]) — This method waits for all promises to settle(resolve/reject) and returns their results as an array of objects. The results will contain a state (fulfilled/rejected) and value, if fulfilled. In case of rejected status, it will return a reason for the error.

    Here is an example of all fulfilled promises:

    Promise.allSettled([promise_1, promise_2, promise_3]).then(result => {
        console.log({result});
    }).catch(error => {
        console.log('There is an Error!');
    });

    Output:

    image-163

    If any of the promises rejects, say, the promise_1,

    let promise_1 = getPromise(POKEMONS_BAD_URL);

    image-164

    The Promise.race() method

    Promise.race([promises]) – It waits for the first (quickest) promise to settle, and returns the result/error accordingly.

    Promise.race([promise_1, promise_2, promise_3]).then(result => {
        console.log(JSON.parse(result));
    }).catch(error => {
        console.log('An Error Occured');
    });

    Output the fastest promise that got resolved:

    image-165

    The Promise.resolve/reject methods

    Promise.resolve(value) – It resolves a promise with the value passed to it. It is the same as the following:

    let promise = new Promise(resolve => resolve(value));

    Promise.reject(error) – It rejects a promise with the error passed to it. It is the same as the following:

    let promise = new Promise((resolve, reject) => reject(error));

    Can we rewrite the PizzaHub example with Promises?

    Sure, let’s do it. Let us assume that the query method will return a promise. Here is an example query() method. In real life, this method may talk to a database and return results. In this case, it is very much hard-coded but serves the same purpose.

    function query(endpoint) {
      if (endpoint === `/api/pizzahub/`) {
        return new Promise((resolve, reject) => {
          resolve({'shopId': '123'});
        })
      } else if (endpoint.indexOf('/api/pizzahub/pizza/') >=0) {
        return new Promise((resolve, reject) => {
          resolve({pizzas: [{'type': 'veg', 'name': 'margherita', 'id': '123'}]});
        })
      } else if (endpoint.indexOf('/api/pizzahub/beverages') >=0) {
        return new Promise((resolve, reject) => {
          resolve({id: '10', 'type': 'veg', 'name': 'margherita', 'beverage': 'coke'});
        })
      } else if (endpoint === `/api/order`) {
        return new Promise((resolve, reject) => {
          resolve({'type': 'veg', 'name': 'margherita', 'beverage': 'coke'});
        })
      }
    }

    Next is the refactoring of our callback hell. To do that, first, we will create a few logical functions:

    // Returns a shop id
    let getShopId = result => result.shopId;
    
    // Returns a promise with pizza list for a shop
    let getPizzaList = shopId => {
      const url = `/api/pizzahub/pizza/${shopId}`;
      return query(url);
    }
    
    // Returns a promise with pizza that matches the customer request
    let getMyPizza = (result, type, name) => {
      let pizzas = result.pizzas;
      let myPizza = pizzas.find((pizza) => {
        return (pizza.type===type && pizza.name===name);
      });
      const url = `/api/pizzahub/beverages/${myPizza.id}`;
      return query(url);
    }
    
    // Returns a promise after Placing the order
    let performOrder = result => {
      let beverage = result.id;
       return query(`/api/order`, {'type': result.type, 'name': result.name, 'beverage': result.beverage});
    }
    
    // Confirm the order
    let confirmOrder = result => {
        console.log(`Your order of ${result.type} ${result.name} with ${result.beverage} has been placed!`);
    }

    Use these functions to create the required promises. This is where you should compare with the callback hell example. This is so nice and elegant.

    function orderPizza(type, name) {
      query(`/api/pizzahub/`)
      .then(result => getShopId(result))
      .then(shopId => getPizzaList(shopId))
      .then(result => getMyPizza(result, type, name))
      .then(result => performOrder(result))
      .then(result => confirmOrder(result))
      .catch(function(error){
        console.log(`Bad luck, No Pizza for you today!`);
      })
    }

    Finally, call the orderPizza() method by passing the pizza type and name, like this:

    orderPizza('veg', 'margherita');
    

    What’s next from here?

    If you are here and have read through most of the lines above, congratulations! You should now have a better grip of JavaScript Promises. All the examples used in this article are in this GitHub repository.

    Next, you should learn about the async function in JavaScript which simplifies things further. The concept of JavaScript promises is best learned by writing small examples and building on top of them.

    Irrespective of the framework or library (Angular, React, Vue, and so on) we use, async operations are unavoidable. This means that we have to understand promises to make things work better.

    Also, I’m sure you will find the usage of the fetch method much easier now:

    fetch('/api/user.json')
    .then(function(response) {
        return response.json();
    })
    .then(function(json) {
        console.log(json); // {"name": "tapas", "blog": "freeCodeCamp"}
    });
    • The fetch method returns a promise. So we can call the .then handler method on it.
    • The rest is about the promise chain which we learned in this article.

    Before we end…

    Thank you for reading this far! Let’s connect. You can @ me on Twitter (@tapasadhikary) with comments.

    You may also like these other articles:

    • JavaScript undefined and null: Let’s talk about it one last time!
    • JavaScript: Equality comparison with ==, === and Object.is
    • The JavaScript `this` Keyword + 5 Key Binding Rules Explained for JS Beginners
    • JavaScript TypeOf – How to Check the Type of a Variable or Object in JS

    That’s all for now. See you again with my next article soon. Until then, please take good care of yourself.



    Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started

    Syntax

    • new Promise( /* executor function: */ function(resolve, reject) { })
    • promise.then(onFulfilled[, onRejected])
    • promise.catch(onRejected)
    • Promise.resolve(resolution)
    • Promise.reject(reason)
    • Promise.all(iterable)
    • Promise.race(iterable)

    Promises are part of the ECMAScript 2015 specification and browser support is limited, with 88% of browsers worldwide supporting it as of July 2017. The following table gives an overview of the earliest browser versions that provide support for promises.

    Chrome Edge Firefox Internet Explorer Opera Opera Mini Safari iOS Safari
    32 12 27 x 19 x 7.1 8

    In environments which do not support them, Promise can be polyfilled. Third-party libraries may also provide extended functionalities, such as automated «promisification» of callback functions or additional methods like progress—also known as notify.

    The Promises/A+ standard website provides a list of 1.0 and 1.1 compliant implementations. Promise callbacks based on the A+ standard are always executed asynchronously as microtasks in the event loop.

    Promise chaining

    The then method of a promise returns a new promise.

    const promise = new Promise(resolve => setTimeout(resolve, 5000));
    
    promise
        // 5 seconds later
        .then(() => 2)
        // returning a value from a then callback will cause
        // the new promise to resolve with this value
        .then(value => { /* value === 2 */ });
    

    Returning a Promise from a then callback will append it to the promise chain.

    function wait(millis) {
        return new Promise(resolve => setTimeout(resolve, millis));
    }
    
    const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
    p.then(() => { /* 10 seconds have passed */ });
    

    A catch allows a rejected promise to recover, similar to how catch in a try/catch statement works. Any chained then after a catch will execute its resolve handler using the value resolved from the catch.

    const p = new Promise(resolve => {throw 'oh no'});
    p.catch(() => 'oh yes').then(console.log.bind(console));  // outputs "oh yes"
    

    If there are no catch or reject handlers in the middle of the chain, a catch at the end will capture any rejection in the chain:

    p.catch(() => Promise.reject('oh yes'))
      .then(console.log.bind(console))      // won't be called
      .catch(console.error.bind(console));  // outputs "oh yes"
    

    On certain occasions, you may want to «branch» the execution of the functions. You can do it by returning different promises from a function depending on the condition. Later in the code, you can merge all of these branches into one to call other functions on them and/or to handle all errors in one place.

    promise
        .then(result => {          
            if (result.condition) {
                return handlerFn1() 
                    .then(handlerFn2);
            } else if (result.condition2) {
                return handlerFn3()
                    .then(handlerFn4);
            } else {
                throw new Error("Invalid result");
            }
        })
        .then(handlerFn5)
        .catch(err => {
            console.error(err);
        });
    

    Thus, the execution order of the functions looks like:

    promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
             |                            ^
             V                            |
             -> handlerFn3 -> handlerFn4 -^            
    

    The single catch will get the error on whichever branch it may occur.

    Introduction

    A Promise object represents an operation which has produced or will eventually produce a value. Promises provide a robust way to wrap the (possibly pending) result of asynchronous work, mitigating the problem of deeply nested callbacks (known as «callback hell»).

    States and control flow

    A promise can be in one of three states:

    • pending — The underlying operation has not yet completed, and the promise is pending fulfillment.
    • fulfilled — The operation has finished, and the promise is fulfilled with a value. This is analogous to returning a value from a synchronous function.
    • rejected — An error has occurred during the operation, and the promise is rejected with a reason. This is analogous to throwing an error in a synchronous function.

    A promise is said to be settled (or resolved) when it is either fulfilled or rejected. Once a promise is settled, it becomes immutable, and its state cannot change. The then and catch methods of a promise can be used to attach callbacks that execute when it is settled. These callbacks are invoked with the fulfillment value and rejection reason, respectively.

    Promise flow diagram

    Example

    const promise = new Promise((resolve, reject) => {
        // Perform some work (possibly asynchronous)
        // ...
    
        if (/* Work has successfully finished and produced "value" */) {
            resolve(value);
        } else {
            // Something went wrong because of "reason"
            // The reason is traditionally an Error object, although
            // this is not required or enforced.
            let reason = new Error(message);
            reject(reason);
    
            // Throwing an error also rejects the promise.
            throw reason;
        }
    });
    

    The then and catch methods can be used to attach fulfillment and rejection callbacks:

    promise.then(value => {
        // Work has completed successfully,
        // promise has been fulfilled with "value"
    }).catch(reason => {
        // Something went wrong,
        // promise has been rejected with "reason"
    });
    

    Note: Calling promise.then(...) and promise.catch(...) on the same promise might result in an Uncaught exception in Promise if an error occurs, either while executing the promise or inside one of the callbacks, so the preferred way would be to attach the next listener on the promise returned by the previous then / catch.

    Alternatively, both callbacks can be attached in a single call to then:

    promise.then(onFulfilled, onRejected);
    

    Attaching callbacks to a promise that has already been settled will immediately place them in the microtask queue, and they will be invoked «as soon as possible» (i.e. immediately after the currently executing script). It is not necessary to check the state of the promise before attaching callbacks, unlike with many other event-emitting implementations.


    Live demo

    Delay function call

    The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds. It is also a trivial way to achieve an asynchronous operation.

    In this example calling the wait function resolves the promise after the time specified as first argument:

    function wait(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));  
    }
    
    wait(5000).then(() => { 
        console.log('5 seconds have passed...');
    });
    

    Waiting for multiple concurrent promises

    The Promise.all() static method accepts an iterable (e.g. an Array) of promises and returns a new promise, which resolves when all promises in the iterable have resolved, or rejects if at least one of the promises in the iterable have rejected.

    // wait "millis" ms, then resolve with "value"
    function resolve(value, milliseconds) {
        return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
    }
    
    // wait "millis" ms, then reject with "reason"
    function reject(reason, milliseconds) {
        return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
    }
    
    Promise.all([
        resolve(1, 5000),
        resolve(2, 6000),
        resolve(3, 7000)    
    ]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.
    
    Promise.all([
        resolve(1, 5000),
        reject('Error!', 6000),
        resolve(2, 7000)
    ]).then(values => console.log(values)) // does not output anything
    .catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.
    

    Non-promise values in the iterable are «promisified».

    Promise.all([
        resolve(1, 5000),
        resolve(2, 6000),
        { hello: 3 }
    ])
    .then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
    

    Destructuring assignment can help to retrieve results from multiple promises.

    Promise.all([
        resolve(1, 5000),
        resolve(2, 6000),
        resolve(3, 7000)
    ])
    .then(([result1, result2, result3]) => {
        console.log(result1);
        console.log(result2);
        console.log(result3);
    });
    

    Waiting for the first of multiple concurrent promises

    The Promise.race() static method accepts an iterable of Promises and returns a new Promise which resolves or rejects as soon as the first of the promises in the iterable has resolved or rejected.

    // wait "milliseconds" milliseconds, then resolve with "value"
    function resolve(value, milliseconds) {
        return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
    }
    
    // wait "milliseconds" milliseconds, then reject with "reason"
    function reject(reason, milliseconds) {
        return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
    }
    
    Promise.race([
        resolve(1, 5000),
        resolve(2, 3000),
        resolve(3, 1000)
    ])
    .then(value => console.log(value)); // outputs "3" after 1 second.
    
    
    Promise.race([
        reject(new Error('bad things!'), 1000),
        resolve(2, 2000)
    ])
    .then(value => console.log(value)) // does not output anything
    .catch(error => console.log(error.message)); // outputs "bad things!" after 1 second
    

    «Promisifying» values

    The Promise.resolve static method can be used to wrap values into promises.

    let resolved = Promise.resolve(2);
    resolved.then(value => {
        // immediately invoked
        // value === 2
    });
    

    If value is already a promise, Promise.resolve simply recasts it.

    let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
    let two = Promise.resolve(one);
    two.then(value => {
        // 1 second has passed
        // value === 2
    });
    

    In fact, value can be any «thenable» (object defining a then method that works sufficiently like a spec-compliant promise). This allows Promise.resolve to convert untrusted 3rd-party objects into trusted 1st-party Promises.

    let resolved = Promise.resolve({
        then(onResolved) {
            onResolved(2);
        }
    });
    resolved.then(value => {
        // immediately invoked
        // value === 2
    });
    

    The Promise.reject static method returns a promise which immediately rejects with the given reason.

    let rejected = Promise.reject("Oops!");
    rejected.catch(reason => {
        // immediately invoked
        // reason === "Oops!"
    });
    

    «Promisifying» functions with callbacks

    Given a function that accepts a Node-style callback,

    fooFn(options, function callback(err, result) { ... });
    

    you can promisify it (convert it to a promise-based function) like this:

    function promiseFooFn(options) {
        return new Promise((resolve, reject) =>
            fooFn(options, (err, result) =>
                // If there's an error, reject; otherwise resolve
                err ? reject(err) : resolve(result)
            )
        );
    }
    

    This function can then be used as follows:

    promiseFooFn(options).then(result => {
        // success!
    }).catch(err => {
        // error!
    });
    

    In a more generic way, here’s how to promisify any given callback-style function:

    function promisify(func) {
        return function(...args) {
            return new Promise((resolve, reject) => {
                func(...args, (err, result) => err ? reject(err) : resolve(result));
            });
        }
    }
    

    This can be used like this:

    const fs = require('fs');
    const promisedStat = promisify(fs.stat.bind(fs));
    
    promisedStat('/foo/bar')
        .then(stat => console.log('STATE', stat))
        .catch(err => console.log('ERROR', err));
    

    Error Handling

    Errors thrown from promises are handled by the second parameter (reject) passed to then or by the handler passed to catch:

    throwErrorAsync()
      .then(null, error => { /* handle error here */ });
    // or
    throwErrorAsync()
      .catch(error => { /* handle error here */ });
    

    Chaining

    If you have a promise chain then an error will cause resolve handlers to be skipped:

    throwErrorAsync()
      .then(() => { /* never called */ })
      .catch(error => { /* handle error here */ });
    

    The same applies to your then functions. If a resolve handler throws an exception then the next reject handler will be invoked:

    doSomethingAsync()
      .then(result => { throwErrorSync(); })
      .then(() => { /* never called */ })
      .catch(error => { /* handle error from throwErrorSync() */ });
    

    An error handler returns a new promise, allowing you to continue a promise chain. The promise returned by the error handler is resolved with the value returned by the handler:

    throwErrorAsync()
      .catch(error => { /* handle error here */; return result; })
      .then(result => { /* handle result here */ });
    

    You can let an error cascade down a promise chain by re-throwing the error:

    throwErrorAsync()
      .catch(error => {
          /* handle error from throwErrorAsync() */
          throw error;
      })
      .then(() => { /* will not be called if there's an error */ })
      .catch(error => { /* will get called with the same error */ });
    

    It is possible to throw an exception that is not handled by the promise by wrapping the throw statement inside a setTimeout callback:

    new Promise((resolve, reject) => {
      setTimeout(() => { throw new Error(); });
    });
    

    This works because promises cannot handle exceptions thrown asynchronously.

    Unhandled rejections

    An error will be silently ignored if a promise doesn’t have a catch block or reject handler:

    throwErrorAsync()
      .then(() => { /* will not be called */ });
    // error silently ignored
    

    To prevent this, always use a catch block:

    throwErrorAsync()
      .then(() => { /* will not be called */ })
      .catch(error => { /* handle error*/ });
    // or
    throwErrorAsync()
      .then(() => { /* will not be called */ }, error => { /* handle error*/ });
    

    Alternatively, subscribe to the unhandledrejection event to catch any unhandled rejected promises:

    window.addEventListener('unhandledrejection', event => {});
    

    Some promises can handle their rejection later than their creation time. The rejectionhandled event gets fired whenever such a promise is handled:

    window.addEventListener('unhandledrejection', event => console.log('unhandled'));
    window.addEventListener('rejectionhandled', event => console.log('handled'));
    var p = Promise.reject('test');
    
    setTimeout(() => p.catch(console.log), 1000);
    
    // Will print 'unhandled', and after one second 'test' and 'handled'
    

    The event argument contains information about the rejection. event.reason is the error object and event.promise is the promise object that caused the event.

    In Nodejs the rejectionhandled and unhandledrejection events are called rejectionHandled and unhandledRejection on process, respectively, and have a different signature:

    process.on('rejectionHandled', (reason, promise) => {});
    process.on('unhandledRejection', (reason, promise) => {});
    

    The reason argument is the error object and the promise argument is a reference to the promise object that caused the event to fire.

    Usage of these unhandledrejection and rejectionhandled events should be considered for debugging purposes only. Typically, all promises should handle their rejections.

    Note: Currently, only Chrome 49+ and Node.js support unhandledrejection and rejectionhandled events.

    Caveats

    Chaining with fulfill and reject

    The then(fulfill, reject) function (with both parameters not null) has unique and complex behavior, and shouldn’t be used unless you know exactly how it works.

    The function works as expected if given null for one of the inputs:

    // the following calls are equivalent
    promise.then(fulfill, null) 
    promise.then(fulfill)
    
    // the following calls are also equivalent
    promise.then(null, reject) 
    promise.catch(reject)
    

    However, it adopts unique behavior when both inputs are given:

    // the following calls are not equivalent!
    promise.then(fulfill, reject)
    promise.then(fulfill).catch(reject)
    
    // the following calls are not equivalent!
    promise.then(fulfill, reject)
    promise.catch(reject).then(fulfill)
    

    The then(fulfill, reject) function looks like it is a shortcut for then(fulfill).catch(reject), but it is not, and will cause problems if used interchangeably. One such problem is that the reject handler does not handle errors from the fulfill handler. Here is what will happen:

    Promise.resolve() // previous promise is fulfilled
        .then(() => { throw new Error(); }, // error in the fulfill handler
            error => { /* this is not called! */ });
    

    The above code will result in a rejected promise because the error is propagated. Compare it to the following code, which results in a fulfilled promise:

    Promise.resolve() // previous promise is fulfilled
        .then(() => { throw new Error(); }) // error in the fulfill handler
        .catch(error => { /* handle error */ });
    

    A similar problem exists when using then(fulfill, reject) interchangeably with catch(reject).then(fulfill), except with propagating fulfilled promises instead of rejected promises.

    Synchronously throwing from function that should return a promise

    Imagine a function like this:

    function foo(arg) {
      if (arg === 'unexepectedValue') {
        throw new Error('UnexpectedValue')
      }
    
      return new Promise(resolve => 
        setTimeout(() => resolve(arg), 1000)
      )
    }
    

    If such function is used in the middle of a promise chain, then apparently there is no problem:

    makeSomethingAsync().
      .then(() => foo('unexpectedValue'))
      .catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
    

    However, if the same function is called outside of a promise chain, then the error will not be handled by it and will be thrown to the application:

    foo('unexpectedValue') // <-- error will be thrown, so the application will crash
      .then(makeSomethingAsync) // <-- will not run
      .catch(err => console.log(err)) // <-- will not catch
    

    There are 2 possible workarounds:

    Return a rejected promise with the error

    Instead of throwing, do as follows:

    function foo(arg) {
      if (arg === 'unexepectedValue') {
        return Promise.reject(new Error('UnexpectedValue'))
      }
    
      return new Promise(resolve => 
        setTimeout(() => resolve(arg), 1000)
      )
    }
    

    Wrap your function into a promise chain

    Your throw statement will be properly caught when it is already inside a promise chain:

    function foo(arg) {
      return Promise.resolve()
        .then(() => {
          if (arg === 'unexepectedValue') {
            throw new Error('UnexpectedValue')
          }
    
          return new Promise(resolve => 
            setTimeout(() => resolve(arg), 1000)
          )
        })
    }
    

    Reconciling synchronous and asynchronous operations

    In some cases you may want to wrap a synchronous operation inside a promise to prevent repetition in code branches. Take this example:

    if (result) { // if we already have a result
      processResult(result); // process it
    } else {
      fetchResult().then(processResult);
    }
    

    The synchronous and asynchronous branches of the above code can be reconciled by redundantly wrapping the synchronous operation inside a promise:

    var fetch = result
      ? Promise.resolve(result)
      : fetchResult();
    
    fetch.then(processResult);
    

    When caching the result of an asynchronous call, it is preferable to cache the promise rather than the result
    itself. This ensures that only one asynchronous operation is required to resolve multiple parallel requests.

    Care should be taken to invalidate cached values when error conditions are encountered.

    // A resource that is not expected to change frequently
    var planets = 'http://swapi.co/api/planets/';
    // The cached promise, or null
    var cachedPromise;
    
    function fetchResult() {
        if (!cachedPromise) {
            cachedPromise = fetch(planets)
                .catch(function (e) {
                    // Invalidate the current result to retry on the next fetch
                    cachedPromise = null;
                    // re-raise the error to propagate it to callers
                    throw e;
                });
        }
        return cachedPromise;
    }
    

    Reduce an array to chained promises

    This design pattern is useful for generating a sequence of asynchronous actions from a list of elements.

    There are two variants :

    • the «then» reduction, which builds a chain that continues as long as the chain experiences success.
    • the «catch» reduction, which builds a chain that continues as long as the chain experiences error.

    The «then» reduction

    This variant of the pattern builds a .then() chain, and might be used for chaining animations, or making a sequence of dependent HTTP requests.

    [1, 3, 5, 7, 9].reduce((seq, n) => {
        return seq.then(() => {
            console.log(n);
            return new Promise(res => setTimeout(res, 1000));
        });
    }, Promise.resolve()).then(
        () => console.log('done'),
        (e) => console.log(e)
    );
    // will log 1, 3, 5, 7, 9, 'done' in 1s intervals
    

    Explanation:

    1. We call .reduce() on a source array, and provide Promise.resolve() as an initial value.
    2. Every element reduced will add a .then() to the initial value.
    3. reduce()‘s product will be Promise.resolve().then(…).then(…).
    4. We manually append a .then(successHandler, errorHandler) after the reduce, to execute successHandler once all the previous steps have resolved. If any step was to fail, then errorHandler would execute.

    Note: The «then» reduction is a sequential counterpart of Promise.all().

    The «catch» reduction

    This variant of the pattern builds a .catch() chain and might be used for sequentially probing a set of web servers for some mirrored resource until a working server is found.

    var working_resource = 5; // one of the values from the source array
    [1, 3, 5, 7, 9].reduce((seq, n) => {
        return seq.catch(() => {
            console.log(n);
            if(n === working_resource) { // 5 is working
                return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
            } else { // all other values are not working
                return new Promise((resolve, reject) => setTimeout(reject, 1000));
            }
        });
    }, Promise.reject()).then(
        (n) => console.log('success at: ' + n),
        () => console.log('total failure')
    );
    // will log 1, 3, 5, 'success at 5' at 1s intervals
    

    Explanation:

    1. We call .reduce() on a source array, and provide Promise.reject() as an initial value.
    2. Every element reduced will add a .catch() to the initial value.
    3. reduce()‘s product will be Promise.reject().catch(...).catch(...).
    4. We manually append .then(successHandler, errorHandler) after the reduce, to execute successHandler once any of the previous steps has resolved. If all steps were to fail, then errorHandler would execute.

    Note: The «catch» reduction is a sequential counterpart of Promise.any() (as implemented in bluebird.js, but not currently in native ECMAScript).

    forEach with promises

    It is possible to effectively apply a function (cb) which returns a promise to each element of an array, with each element waiting to be processed until the previous element is processed.

    function promiseForEach(arr, cb) {
      var i = 0;
    
      var nextPromise = function () {
        if (i >= arr.length) {
          // Processing finished.
          return;
        }
    
        // Process next function. Wrap in `Promise.resolve` in case
        // the function does not return a promise
        var newPromise = Promise.resolve(cb(arr[i], i));
        i++;
        // Chain to finish processing.
        return newPromise.then(nextPromise);
      };
    
      // Kick off the chain.
      return Promise.resolve().then(nextPromise);
    };
    

    This can be helpful if you need to efficiently process thousands of items, one at a time. Using a regular for loop to create the promises will create them all at once and take up a significant amount of RAM.

    Performing cleanup with finally()

    There is currently a proposal (not yet part of the ECMAScript standard) to add a finally callback to promises that will be executed regardless of whether the promise is fulfilled or rejected. Semantically, this is similar to the finally clause of the try block.

    You would usually use this functionality for cleanup:

    var loadingData = true;
    
    fetch('/data')
        .then(result => processData(result.data))
        .catch(error => console.error(error))
        .finally(() => {
            loadingData = false;
        });
    

    It is important to note that the finally callback doesn’t affect the state of the promise. It doesn’t matter what value it returns, the promise stays in the fulfilled/rejected state that it had before. So in the example above the promise
    will be resolved with the return value of processData(result.data) even though the finally callback returned undefined.

    With the standardization process still being in progress, your promises implementation most likely won’t support finally callbacks out of the box. For synchronous callbacks you can add this functionality with a polyfill however:

    if (!Promise.prototype.finally) {
        Promise.prototype.finally = function(callback) {
            return this.then(result => {
                callback();
                return result;
            }, error => {
                callback();
                throw error;
            });
        };
    }
    

    Asynchronous API request

    This is an example of a simple GET API call wrapped in a promise to take advantage of its asynchronous functionality.

    var get = function(path) {
      return new Promise(function(resolve, reject) {
        let request = new XMLHttpRequest();
        request.open('GET', path);
        request.onload = resolve;
        request.onerror = reject;
        request.send();
      });
    };
    

    More robust error handling can be done using the following onload and onerror functions.

    request.onload = function() {
      if (this.status >= 200 && this.status < 300) {
        if(request.response) {
          // Assuming a successful call returns JSON
          resolve(JSON.parse(request.response));
        } else {
          resolve();
      } else {
        reject({
          'status': this.status,
          'message': request.statusText
        });
      }
    };
    
    request.onerror = function() {
      reject({
        'status': this.status,
        'message': request.statusText
      });
    };
    

    Using ES2017 async/await

    The same example above, Image loading, can be written using async functions. This also allows using the common try/catch method for exception handling.

    Note: as of April 2017, the current releases of all browsers but Internet Explorer supports async functions.

    function loadImage(url) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.addEventListener('load', () => resolve(img));
            img.addEventListener('error', () => {
                reject(new Error(`Failed to load ${url}`));
            });
            img.src = url;
        });
    }
    
    (async () => {
    
        // load /image.png and append to #image-holder, otherwise throw error
        try {
            let img = await loadImage('http://example.com/image.png');
            document.getElementById('image-holder').appendChild(img);
        }
        catch (error) {
            console.error(error);
        }
    
    })();
    

    JavaScript promises allow asynchronous code to use structured error handling. The promise chains are served as a great way of error handling.

    Whenever a promise rejects, the control jumps to the nearest rejection handler.
    One of the most useful methods of error-handling is .catch.

    As it was already mentioned, .catch is one of the most useful methods for error handling in JavaScript.

    Let’s view a case, in which the URL to fetch is wrong (no such site), and the .catch method handles it:

    w3docs logo
    Javascript promise fetch is wrong and .catch method

    fetch(‘https://noSuchServer.someText’) // rejects
    .then(response => response.json())
    .catch(err => console.log(err)) // TypeError: failed to fetch (the text may vary)

    But note that .catch is not immediate. It might appear after one or several .then.

    Everything might be correct with the site, but the response is not valid JSON.
    The simplest way of catching all the errors is to append .catch to the end of the chain. Here is an example:

    w3docs logo
    Javascript promise fetch is wrong and .catch method

    fetch(‘/promiseChaining/user.json’)
    .then(response => response.json())
    .then(user => fetch(`https://api.github.com/users/${user.name}`))
    .then(response => response.json())
    .then(user => new Promise((resolve, reject) => {
    let img = document.createElement(‘img’);
    img.src = user.avatarUrl;
    img.className = «promiseAvatarExample»;
    document.body.append(img);
    setTimeout(() => {
    img.remove();
    resolve(user);
    }, 3000);
    }))
    .catch(error => console.log(error.message));

    Usually, .catch doesn’t trigger. But, in case any of the promises, as mentioned earlier, rejects, it will catch it.

    There is an invisible try..catch around the code of a promise handler and promise executor. In case of an exception, it will be treated as a rejection.

    It is shown in the following code:

    new Promise((resolve, reject) => {
      throw new Error("Error!!");
    }).catch(console.log); // Error: Error!!

    It operates the same as this code:

    w3docs logo
    Javascript try..catch

    new Promise((resolve, reject) => {
    reject(new Error(«Error!!»));
    }).catch(console.log); // Error: Error!!

    The invisible try..catch will catch the error and transform it into a rejected promise. It can happen both in the executor function and its handlers. In case you throw inside a .then handler, it means a rejected promise, and the control jumps to the closest error handler.

    An example will look like this:

    w3docs logo
    Javascript try..catch

    new Promise((resolve, reject) => {
    resolve(«Yes»);
    }).then((result) => {
    throw new Error(«Error!!»); // rejects the promise
    }).catch(console.log); // Error: Error!!

    That may happen to all the errors, not just ones caused by the throw statement.

    We can consider a programming error as an example:

    w3docs logo
    Javascript throw statement

    new Promise((resolve, reject) => {
    resolve(«Yes»);
    }).then((result) => {
    someFunction(); // no such function
    }).catch(console.log); // ReferenceError: someFunction is not defined

    The final .catch will catch both explicit rejections and accidental errors in the handlers.

    As it was already stated, .catch at the end of the promise chain is equivalent to try..catch. You may have as many .then handlers as you like, then use a single .catch at the end of the chain for handling all the errors.

    The regulartry..catch allows you to analyze an error and rethrow it if it can’t be handled. A similar situation is possible for promises.

    If you throw inside .catch, then the control will go to the next nearest error handler. If you handle the error and finish normally, it will continue to the next nearest successful .then handler.

    The example below illustrates the successful error-handling with .catch:

    w3docs logo
    Javascript error-handling with .catch

    // the execution: catch -> then
    new Promise((resolve, reject) => {
    throw new Error(«Error!!»);
    }).catch(function (error) {
    console.log(«The error-handling, continue normally»);
    }).then(() => console.log(«The next successful handler runs»));

    In the example above, the .catch block finishes normally. Hence, the next effective .then is called.

    Now let’s check out another situation with .catch. The handler (*) catches the error but is not capable of handling it:

    w3docs logo
    Javascript error-handling with .catch console.log

    // the execution: catch -> catch -> then
    new Promise((resolve, reject) => {
    throw new Error(«Error!!»);
    }).catch(function (error) { // (*)
    if (error instanceof URIError) {
    // handle
    } else {
    console.log(«Can’t handle such a error»);
    throw error; // throwing this or that error jumps to the next catch
    }
    }).then(function () {
    /* doesn’t run here */
    }).catch(error => { // (**)
    console.log(`The unknown error: ${error}`);
    // do not return anything => execution goes the usual way
    });

    The execution jumps from the initial .catch (*) to the following one down the chain.

    In this section, we will examine the cases when errors are not handled.

    Let’s see that you have forgotten to append .catch to the end of the chain.

    Here is an example:

    new Promise(function () {
        noSuchFunc(); // Error here, no such function
      })
      .then(() => {
        // successful promise handlers
      }); // no append .catch at the end

    If there is an error, the promise will be rejected. The execution will jump to the nearest rejection handler. But there exists none, and the error will get “stuck”.There isn’t any code for handling it.

    So, what will happen if an error is not caught by try..catch? The script will collapse with a console message. Things like that occur with unhandled promise rejections.

    The engine of JavaScript usually tracks this kind of rejections, generating a global error.

    For catching such errors in the browser, you can use the event unhandledRejection, as follows:

    window.addEventListener('unhandledRejection', function (event) {
      // the event object has two special properties
      console.log(event.promise); // [object Promise] - error
      console.log(event.reason); // Error: Error!! - the unhandled error
    });
    new Promise(function () {
      throw new Error("Error!!");
    }); // no catch to handle the error

    So, in case there is an error, and no .catch can be found, the unhandledRejection will trigger getting the event object with the information regarding the error.

    As a rule, this kind of errors are unrecoverable. The most proper solution in such circumstances is to inform the user about it, reporting the incident to the server.

    Non-browser environments, such as Node.js, include other options for tracking unhandled errors.

    One of the most significant assets of using promises is the way they allow you to handle errors.

    Errors in the promises can be handled with .catch: no matter it’s a reject() call or an error thrown in a handler. It would be best if you put .catch precisely in the places where you want to handle errors. The handler analyzes the errors rethrowing the ones that are unknown (for example, programming mistakes).

    In any other case, you need to have unhandledRejection event handler ( for browsers and analogs of different environments). It will track unhandled errors informing the user about them. It will help you avoid the collapse of your app.

    Понравилась статья? Поделить с друзьями:
  • Prototype 2 mainwin32 error
  • Prototype 2 error could not load prototype2engine dll
  • Proton vpn network error linux
  • Protocol error with rcmd
  • Promag 50 ошибка 321