Repackaging XMLHttpRequest
The JavaScript fetch
API has been around for a few
years now, but a couple of browsers (Safari and iOS Safari, for
example) have only supported it for a little over a year now.
Prior to fetch
, we used XMLHttpRequest
to request data in JavaScript. If you're a bit late to the game
because you're still supporting some of those older browser
versions, here's a step-by-step guide for how XMLHttpRequest
can be repackaged into the fetch
API.
Let's start with a simple XMLHttpRequest
example. We
have a GET request using a particular
URL. (For the sake of brevity, I'm not attempting to handle all
possible error states in these examples.)
let xhr = new XMLHttpRequest(); xhr.addEventListener("load", () => { console.log(xhr.responseText); }); xhr.open("GET", "/assets/post-data/xhr.txt"); xhr.send();
We can package this up into a nice function that accepts two parameters - the URL and a callback function with the response.
function getRequest(url, callback) { let xhr = new XMLHttpRequest(); xhr.addEventListener("load", () => { callback(xhr.responseText); }); xhr.open("GET", url); xhr.send(); } getRequest("/assets/post-data/xhr.txt", response => { console.log(response); });
Using our getRequest
function becomes a very
convenient way to request data. However, we're assuming we
won't run into any error cases with our request. What if we
wanted to support another callback in case there's an error?
function getRequest(url, success, failure) { let xhr = new XMLHttpRequest(); xhr.addEventListener("load", () => { success(xhr.responseText); }); xhr.addEventListener("error", event => { failure(event); }); xhr.open("GET", url); xhr.send(); } getRequest("/assets/post-data/xhr.txt", response => { console.log(response); }, error => { console.log(error); });
Now we have something very similar to a Promise
. We
call our getRequest
function and execute either
the success or failure callback. If our function actually
returned a Promise
, calling it would look something
like this:
getRequest("/assets/post-data/xhr.txt") .then(response => { console.log(response); }) .catch(error => { console.log(error); });
And we would implement our function to return a Promise
by wrapping its current implementation within a Promise
.
function getRequest(url, success, failure) { return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.addEventListener("load", () => { resolve(xhr.responseText); // success function }); xhr.addEventListener("error", event => { reject(event); // failure function }); xhr.open("GET", url); xhr.send(); }); }
Just rename getRequest
to fetch
and
you have a very basic implementation of the fetch
API. You can go back and add the necessary error handling as well
as support for passing in request options and receiving more
complex Response
objects that more fully describe
the HTTP response.
fetch("/assets/post-data/xhr.txt") .then(response => { return response.text(); }) .then(text => { console.log(text); }) .catch(error => { console.log(error); });
Congratulations! You should now be able to see how we moved from
XMLHttpRequest
to fetch
.