Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙ Pengaturan Proxy Target

20 août 2021

Fetch: Download progress

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 – true lorsque la lecture est terminĂ©e, sinon false.
  • value – un tableau typĂ© d’octets : Uint8Array.
Veuillez noter :

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 :

  1. Nous effectuons un fetch comme d’habitude, mais au lieu d’appeler response.json(), nous obtenons un lecteur de flux response.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.

  2. 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.

  3. 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 de response.json() ou d’une autre maniĂšre (vous pouvez essayer, il y aura une erreur).

  4. À la fin, nous avons chunks – un tableau de morceaux d’octets Uint8Array. 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 :

    1. Nous crĂ©ons chunksAll = new Uint8Array(receivedLength) – un tableau de mĂȘme type avec la longueur combinĂ©e.
    2. Ensuite nous utilisons la mĂ©thode .set(chunk, position) pour copier chaque chunk l’un aprĂšs l’autre.
  5. 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.

Carte du tutoriel

Commentaires

lire ceci avant de commenter

  • Si vous avez des amĂ©liorations Ă  suggĂ©rer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de prĂ©ciser.
  • Pour insĂ©rer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen
)