La méthode fetch permet de suivre la progression du téléchargement.
Veuillez noter: il nây a actuellement aucun moyen pour fetch de suivre la progression du tĂ©lĂ©chargement. Ă cette fin, veuillez utiliser XMLHttpRequest, nous le couvrirons plus tard.
Pour suivre la progression du tĂ©lĂ©chargement, nous pouvons utiliser la propriĂ©tĂ© response.body. Câest ReadableStream â un objet spĂ©cial qui fournit le corps morceau par morceau, comme il vient. Les flux lisibles sont dĂ©crits dans la spĂ©cification Streams API.
Contrairement Ă response.text(), response.json() et Ă dâautres mĂ©thodes, response.body donne un contrĂŽle total sur le processus de lecture, et nous pouvons compter la quantitĂ© consommĂ©e Ă tout moment.
Voici lâesquisse de code qui lit la rĂ©ponse de response.body :
// au lieu de response.json() et d'autres méthodes
const reader = response.body.getReader();
// boucle infinie pendant le téléchargement du corps
while(true) {
// done is true for the last chunk
// value is Uint8Array of the chunk bytes
const {done, value} = await reader.read();
if (done) {
break;
}
console.log(`Received ${value.length} bytes`)
}
Le rĂ©sultat de lâappel await reader.read() est un objet avec deux propriĂ©tĂ©s :
doneâtruelorsque la lecture est terminĂ©e, sinonfalse.valueâ un tableau typĂ© dâoctets :Uint8Array.
LâAPI Streams dĂ©crit Ă©galement lâitĂ©ration asynchrone sur ReadableStream avec la boucle for wait..of, mais elle nâest pas encore largement prise en charge (voir les problĂšmes de navigateurs), nous utilisons donc la boucle while.
Nous recevons des morceaux de rĂ©ponse dans la boucle, jusquâĂ ce que le chargement se termine, câest-Ă -dire: jusquâĂ ce que done devienne true.
Pour enregistrer la progression, nous avons juste besoin dâajouter la longueur de la value de chaque fragment reçu au compteur.
Voici lâexemple de travail complet qui obtient la rĂ©ponse et enregistre la progression dans la console, plus dâexplications Ă suivre :
// Ătape 1: dĂ©marrez la rĂ©cupĂ©ration et obtenir un lecteur
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
const reader = response.body.getReader();
// Ătape 2: obtenir la longueur totale
const contentLength = +response.headers.get('Content-Length');
// Ătape 3: lecture des donnĂ©es
let receivedLength = 0; // reçu autant d'octets en ce moment
let chunks = []; // tableau de morceaux binaires reçus (comprend le corps)
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
console.log(`Received ${receivedLength} of ${contentLength}`)
}
// Ătape 4: concatĂ©ner des morceaux en un seul Uint8Array
let chunksAll = new Uint8Array(receivedLength); // (4.1)
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position); // (4.2)
position += chunk.length;
}
// Ătape 5: dĂ©coder en une chaĂźne de caractĂšres
let result = new TextDecoder("utf-8").decode(chunksAll);
// Nous avons fini !
let commits = JSON.parse(result);
alert(commits[0].author.login);
Expliquons cela étape par étape :
-
Nous effectuons un
fetchcomme dâhabitude, mais au lieu dâappelerresponse.json(), nous obtenons un lecteur de fluxresponse.body.getReader().Veuillez noter que nous ne pouvons pas utiliser ces deux mĂ©thodes pour lire la mĂȘme rĂ©ponse : utilisez un lecteur ou une mĂ©thode de rĂ©ponse pour obtenir le rĂ©sultat.
-
Avant la lecture, nous pouvons dĂ©terminer la longueur complĂšte de la rĂ©ponse Ă partir de lâen-tĂȘte
Content-Length.Il peut ĂȘtre absent pour les requĂȘtes cross-origin (voir le chapitre Fetch: RequĂȘtes Cross-Origin), techniquement, un serveur nâa pas Ă le configurer. Mais gĂ©nĂ©ralement, câest Ă sa place.
-
Appel de
await reader.read()jusquâĂ ce que ce soit fait.Nous rassemblons des blocs de rĂ©ponse dans le tableau
chunks. Câest important, car une fois la rĂ©ponse consommĂ©e, nous ne pourrons pas la ârelireâ Ă lâaide deresponse.json()ou dâune autre maniĂšre (vous pouvez essayer, il y aura une erreur). -
Ă la fin, nous avons
chunksâ un tableau de morceaux dâoctetsUint8Array. Nous devons les joindre en un seul rĂ©sultat. Malheureusement, il nây a pas de mĂ©thode unique qui les concatĂšne, donc il y a du code pour le faire :- Nous crĂ©ons
chunksAll = new Uint8Array(receivedLength)â un tableau de mĂȘme type avec la longueur combinĂ©e. - Ensuite nous utilisons la mĂ©thode
.set(chunk, position)pour copier chaquechunklâun aprĂšs lâautre.
- Nous créons
-
Nous avons le résultat dans
chunksAll. Câest un tableau dâoctets cependant, pas une chaĂźne de caractĂšres.Pour crĂ©er une chaĂźne de caractĂšres, nous devons interprĂ©ter ces octets. Le TextDecoder intĂ©grĂ© fait exactement cela. Ensuite, nous pouvons
JSON.parse, si nĂ©cessaire.Et si nous avions besoin dâun contenu binaire au lieu dâune chaĂźne de caractĂšres ? Câest encore plus simple. Remplacez les Ă©tapes 4 et 5 par une seule ligne qui crĂ©e un
BlobĂ partir de tous les morceaux :let blob = new Blob(chunks);
Ă la fin, nous avons le rĂ©sultat (sous forme de chaĂźne de caractĂšres ou dâobjet blob, selon ce qui est pratique) et le suivi des progrĂšs dans le processus.
Encore une fois, veuillez noter que ce nâest pas pour la progression en upload (pas de possibilitĂ© actuellement avec fetch), seulement pour la progression en download.
De plus, si la taille est inconnue, nous devrions vĂ©rifier receiveLength dans la boucle et la briser une fois quâelle atteint une certaine limite. Pour que les chunks ne dĂ©bordent pas de mĂ©moire.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)