Introduction à fetch()

L'API fetch() atterrit dans l'objet window et cherche à remplacer les requêtes XHR

XMLHttpRequest trop long

fetch() vous permet d'effectuer des requêtes réseau semblables à XMLHttpRequest (XHR). La principale différence est que l'API Fetch utilise des promesses, ce qui permet une API plus simple et plus propre, évitant ainsi l'enfer des rappels et devoir mémoriser l'API complexe XMLHttpRequest.

Navigateurs pris en charge

  • 42
  • 14
  • 39
  • 10.1

Source

L'API Fetch est disponible dans le champ d'application global Service Worker depuis Chrome 40, mais elle sera activée dans le champ d'application de la fenêtre dans Chrome 42. Il existe également un polyfill de GitHub plutôt que d'extraction que vous pouvez utiliser aujourd'hui.

Si vous n'avez jamais utilisé les promesses auparavant, consultez Présentation des promesses JavaScript.

Demande de récupération de base

Commençons par comparer un exemple simple implémenté avec XMLHttpRequest, puis avec fetch. Nous voulons simplement demander une URL, obtenir une réponse et l'analyser au format JSON.

XMLHttpRequest

Un XMLHttpRequest nécessite que deux écouteurs soient définis pour gérer les cas de réussite et d'erreur, ainsi qu'un appel à open() et send(). Exemple tiré de la documentation MDN

function reqListener() {
    var data = JSON.parse(this.responseText);
    console.log(data);
}

function reqError(err) {
    console.log('Fetch Error :-S', err);
}

var oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

Méthode fetch

Notre demande de récupération ressemble un peu à ceci:

fetch('./api/some.json')
    .then(
    function(response) {
        if (response.status !== 200) {
        console.log('Looks like there was a problem. Status Code: ' +
            response.status);
        return;
        }

        // Examine the text in the response
        response.json().then(function(data) {
        console.log(data);
        });
    }
    )
    .catch(function(err) {
    console.log('Fetch Error :-S', err);
    });

Nous commençons par vérifier que l'état de la réponse est 200 avant de l'analyser au format JSON.

La réponse à une requête fetch() est un objet Stream, ce qui signifie que lorsque nous appelons la méthode json(), une promesse est renvoyée, car la lecture du flux s'effectue de manière asynchrone.

Métadonnées de réponse

Dans l'exemple précédent, nous avons examiné l'état de l'objet Response (Réponse) et expliqué comment analyser la réponse au format JSON. D'autres métadonnées auxquelles nous pouvons vouloir accéder, telles que les en-têtes, sont illustrées ci-dessous.

fetch('users.json').then(function(response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));

    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
});

Types de réponses

Lorsque nous effectuons une requête de récupération, la réponse reçoit le response.type "basic", "cors" ou "opaque". Ces types indiquent l'origine de la ressource et peuvent être utilisés pour indiquer comment traiter l'objet de réponse.

Lorsqu'une requête est effectuée pour une ressource de même origine, la réponse est de type basic. Il n'existe aucune restriction sur ce que vous pouvez afficher à partir de la réponse.

Si une requête est effectuée pour une ressource d'une autre origine qui renvoie les en-têtes COR, le type est cors. Les réponses cors et basic sont presque identiques, sauf qu'une réponse cors limite les en-têtes que vous pouvez afficher à Cache-Control, Content-Language, Content-Type, Expires, Last-Modified et Pragma.

Une réponse opaque concerne une requête effectuée pour une ressource d'une origine différente qui ne renvoie pas d'en-têtes CORS. Avec une réponse opaque, nous ne pouvons pas lire les données renvoyées ni afficher l'état de la requête, ce qui signifie que nous ne pouvons pas vérifier si la requête a abouti ou non.

Vous pouvez définir un mode pour une requête d'exploration afin que seules certaines requêtes soient résolues. Les modes que vous pouvez définir sont les suivants:

  • same-origin n'aboutit que pour les requêtes concernant des éléments de même origine. Toutes les autres requêtes seront refusées.
  • cors autorise les requêtes pour des éléments de même origine et d'autres origines qui renvoient les en-têtes COR appropriés.
  • cors-with-forced-preflight effectue toujours une vérification préliminaire avant d'envoyer la requête proprement dite.
  • no-cors est destiné à envoyer des requêtes à d'autres origines qui n'ont pas d'en-têtes CORS et qui génèrent une réponse opaque. Toutefois, comme indiqué, cela n'est pas possible pour le moment dans le champ d'application global de la fenêtre.

Pour définir le mode, ajoutez un objet d'options en tant que deuxième paramètre de la requête fetch, puis définissez le mode dans cet objet:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
    .then(function(response) {
    return response.text();
    })
    .then(function(text) {
    console.log('Request successful', text);
    })
    .catch(function(error) {
    log('Request failed', error)
    });

Chaîne de promesses

L'une des grandes caractéristiques des promesses est la possibilité de les enchaîner. L'extraction vous permet de partager la logique entre les requêtes d'extraction.

Si vous utilisez une API JSON, vous devez vérifier l'état et analyser le fichier JSON pour chaque réponse. Vous pouvez simplifier votre code en définissant l'état et l'analyse JSON dans des fonctions distinctes qui renvoient des promesses, ce qui vous évite de vous préoccuper uniquement de la gestion des données finales et du cas d'erreur.

function status(response) {
    if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
    } else {
    return Promise.reject(new Error(response.statusText))
    }
}

function json(response) {
    return response.json()
}

fetch('users.json')
    .then(status)
    .then(json)
    .then(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

Nous définissons la fonction status qui vérifie le champ response.status et renvoie le résultat de Promise.resolve() ou de Promise.reject(), qui renvoie une promesse résolue ou refusée. Il s'agit de la première méthode appelée dans la chaîne fetch(). Si elle est résolue, nous appelons ensuite la méthode json(), qui renvoie à nouveau une promesse à partir de l'appel response.json(). Nous avons ensuite un objet du fichier JSON analysé. Si l'analyse échoue, la promesse est rejetée et l'instruction "catch" s'exécute.

L'avantage, c'est que vous pouvez partager la logique entre toutes vos requêtes de récupération, ce qui facilite la gestion, la lecture et le test du code.

Demande POST

Il n'est pas rare que les applications Web souhaitent appeler une API avec une méthode POST et fournir certains paramètres dans le corps de la requête.

Pour ce faire, nous pouvons définir les paramètres method et body dans les options fetch().

fetch(url, {
    method: 'post',
    headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
    })
    .then(json)
    .then(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

Envoyer des identifiants à l'aide d'une requête de récupération

Si vous souhaitez effectuer une requête de récupération avec des identifiants tels que des cookies, vous devez définir le credentials de la requête sur "include".

fetch(url, {
    credentials: 'include'
})

Questions fréquentes

Comment annuler une requête fetch() ?

Il n'existe actuellement aucun moyen d'annuler une récupération, mais ce sujet est abordé sur GitHub. H/T @jaffathecake pour ce lien.

Y a-t-il un polyfill ?

GitHub comporte un polyfill pour l'extraction. H/T @Nexii.

Pourquoi "no-cors" est-il disponible dans les service workers, mais pas dans la fenêtre ?

En raison d'un problème de sécurité, cliquez ici pour en savoir plus.