In JavaScript how do I/should I use async/await with XMLHttpRequest?

jkupczak picture jkupczak · Feb 25, 2018 · Viewed 31.7k times · Source

Full disclosure: I'd qualify myself as having intermediate JavaScript knowledge. So this is slightly above my experience level at this time.

I've got a Google Chrome Extension that does an AJAX request for a local file:/// as soon as a page loads. After I get the response back from the request I use the returned code in several functions later on in my code. Most of the time I get the response back before my code that needs it runs. But sometimes I don't and everything breaks.

Now, I assume I could just throw all of the relevant code inside of the xhr.onload below. But that seems really inefficient? I have a lot of moving parts that rely on the response and it seems bad to put them all in there.

I've perused several articles related to async/await and I'm having trouble grasping the concept. I'm also not 100% positive I'm looking at this the right way. Should I even be considering using async/await?

Here is the code for my AJAX request.

  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.onload = function(e) {
    code = xhr.response;
  };
  xhr.onerror = function () {
    console.error("** An error occurred during the XMLHttpRequest");
  };
  xhr.send();

Let's say I've got a bunch of functions that need to fire afterwards later on in my code. Right now they just look like:

function doTheThing(code) {
  // I hope the response is ready.
}

What's the best way to approach this? FYI, the Fetch API isn't an option.

Here's a high level view of how my code is structured.

// AJAX request begins.

// ...

// A whole bunch of synchronous code that isn't dependant on 
// the results of my AJAX request. (eg. Creating and appending
// some new DOM nodes, calculating some variables) I don't want
// to wait for the AJAX response when I could be building this stuff instead.

// ...

// Some synchronous code that is dependant on both my AJAX 
// request and the previous synchronous code being complete.

// ...

// Some more synchronous code that needs the above line to 
// be complete.

Answer

Thắng Trần Xuân picture Thắng Trần Xuân · Feb 25, 2018

I usually do async/await like this:

async function doAjaxThings() {
    // await code here
    let result = await makeRequest("GET", url);
    // code below here will only execute when await makeRequest() finished loading
    console.log(result);
}
document.addEventListener("DOMContentLoaded", function () {
    doAjaxThings();
    // create and manipulate your DOM here. doAjaxThings() will run asynchronously and not block your DOM rendering
    document.createElement("...");
    document.getElementById("...").addEventListener(...);
});

Promisified xhr function here:

function makeRequest(method, url) {
    return new Promise(function (resolve, reject) {
        let xhr = new XMLHttpRequest();
        xhr.open(method, url);
        xhr.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                resolve(xhr.response);
            } else {
                reject({
                    status: this.status,
                    statusText: xhr.statusText
                });
            }
        };
        xhr.onerror = function () {
            reject({
                status: this.status,
                statusText: xhr.statusText
            });
        };
        xhr.send();
    });
}