Async / Promise Issue

Scott Taylor
Scott Taylor used Ask the Experts™
on
I am trying to understand node/javascript async / promise features.  While doing this I ran across an example that confuses me.  Here is the example, and the questions are below:
From https://codeburst.io/javascript-promises-explained-with-simple-real-life-analogies-dd6908092138

const loadImage = url => {
  return new Promise(function(resolve, reject) {

    //Open a new XHR
    var request = new XMLHttpRequest();
    request.open('GET', url);

    // When the request loads, check whether it was successful
    request.onload = function() {
      if (request.status === 200) {
        // If successful, resolve the promise
        resolve(request.response);
      } else {
        // Otherwise, reject the promise
        reject(Error('An error occurred while loading image. error code:' + request.statusText));
      }
    };

    request.send();
  });

};

Open in new window


1. Why create a promise for this?  Isn't XMLHttpRequest already async?  It makes a request, and then you feed onload a function to call when it is done.
2. onload documentation says, "to be executed when the request completes successfully".  So in the example above onload is used for a resolve or a reject.  If onload only fires on success how would the failure portion of the IF (line 13) every be reached?
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
1. Converting the XHR request to a promise makes your code easier to manage. It means you can put the request inside a function and then use the .then() of the promise in the calling code or async / await which makes the code a lot neater.
Consider this
function loadProducts() {
  getApi('products')
    .then(products => // do something useful);
}

Open in new window

Or using async / await
async function loadProducts() {
  var products = await getApi('products');
  products.forEach(product => // do something useful with the product);
}

Open in new window

as opposed to
function loadProducts() {
   var xhr = XMLHttpRequest();
   xhr.addEventListener('load', data => // do something useful with data);
   xhr.open('GET', '/api/products/);
}

Open in new window

The first method allows us to build a generic api that we can re-use for all requests to the server without having to pass callbacks around. Promises can also be chained so you can return a value from one promise to another promise chained to the first - not a consideration in this case.
I would have to see the reason for using XMLHttpRequest to download images to say why it was done this way - if it were me I would just add an event handler to the image and then set the src attribute to the image.

2. The onload fires when there is a successful return - however the error on line 13 does not relate to an error in transmission but rather an error condition as determined by the server. In other words the request to the server and the return completes successfully - but the server can return a response indicating that it rejected the request (40x) or there was an error (50x) - this has nothing to do with the async operation which completed successfully.
In this case the code is specifically testing for a 200 return and assumes if it does not get it the server rejected the request or had an error.

If you want to check for an error in the actual connection you need to setup an event listener on the error event

request.addEventListener("error", transferFailed);
function transferFailed(...) {
  // handle error
}

Open in new window

You can read more about this here https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

Author

Commented:
Thank you.  That cleared up both of those issues that was haunting me while I was learning the area of the language.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
You are welcome.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial