Browsers have supported fetch()
for years now (except Internet Explorer), but I still see many developers use classic XHR-based "ajax".
Why is that? I think — partly — it's because fetch()
is missing timeout
and an easier way of handling errors. Yet, developers do want to use it because of its simplicity.
In other words: it's a fetch-22 situation (bad pun intended!)
I've written a small module, fetch22(), which extends the fetch() init-object with:
- callback(true|false) : function to call when fetch starts(true) and ends(false)
- errorHandler(error) : custom function to run if an error occurs
- errorList : Array of status-codes to manually trigger errors
- parser(response) : custom function to parse the response, default will use .json() or .text(), depending on response content-type
- parserArgs : Array of extra arguments to send to the custom parser after response
- timeout : period in milliseconds to allow before a Timeout Error. Default is 9999ms
The module itself can be grabbed here, and a Pen with examples can be seen here (but go to Codepen and see it in full-screen):
Here are some of the examples from the demo:
Custom callback
The custom callback is called twice, once when the fetch initiates, and then when the fetch is complete done:
function startStop(bool) {
if (bool) {
console.log('START'}
else {
console.log('STOP');
}
}
Custom ErrorHandler
Receives the error-object as it's only param:
function handleError(error) {
console.error(error.name, error.message);
}
Custom parser
The default parser returns json or text, depending on content-type
. An example of a custom parser, finding a <symbol>
by id
in an svg:
async function getSymbolFromSVG(response, id) {
const text = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(text, "text/xml");
const svg = doc.getElementById(id);
return svg.outerHTML.toString();
}
Hope it will be as useful for you, as it has been for me.
Thanks for reading, and happy coding!
Top comments (6)
Hi there, very interesting topic, thanks for this library!
You can use a combination of setTimeout, AbortController and the Fetch API to achieve a similar result, while still leveraging the power of promises.
This is a very great use-case for using this obscure AbortController. Although you don't really manage what error message is thrown, you can still detect the
instanceof
the error which will beAbortError
in that case. See MDN.It's exactly what I'm using, if you look at the code - it just adds the AbortError to the same errorHandler.
The result is a promise ;-)
You are correct, I didn't look at your code, very well done then!
I'll let this code snippet for people wanting an alternative without the start/stop callback or the error list.
👍
Can you show the benefit of the callback and errorHandler and parser over the then/catch of promise ?
I think it's just an easier syntax, parsing one init-object with these extra options. The result itself is a Promise, the start/stop callback is called on init, and in the
.finally()
-block. The errorHandler takes care of "AbortErrors" (timeout) as well: