web-dev-qa-db-fra.com

Comment puis-je récupérer un tableau d'URL avec Promise.all?

Si j'ai un tableau d'URL:

var urls = ['1.txt', '2.txt', '3.txt']; // these text files contain "one", "two", "three", respectively.

Et je veux construire un objet qui ressemble à ceci:

var text = ['one', 'two', 'three'];

J’essaie d’apprendre à faire cela avec fetch, qui renvoie bien sûr Promises.

Certaines choses que j’ai essayées ne pas fonctionnent:

var promises = urls.map(url => fetch(url));
var texts = [];
Promise.all(promises)
  .then(results => {
     results.forEach(result => result.text()).then(t => texts.Push(t))
  })

Cela ne semble pas correct et, dans tous les cas, cela ne fonctionne pas - je ne me retrouve pas avec un tableau ['un', 'deux', 'trois'].

Utilise Promise.all la bonne approche ici?

41
user2467065

Oui, Promise.all est la bonne approche, mais vous en avez réellement besoin deux fois si vous voulez d'abord fetch toutes les urls puis obtenir tous les texts (qui sont à nouveau des promesses pour le corps de la réponse) . Donc tu devrais faire

Promise.all(urls.map(u=>fetch(u))).then(responses =>
    Promise.all(responses.map(res => res.text()))
).then(texts => {
    …
})

Votre code actuel ne fonctionne pas car forEach ne renvoie rien (ni tableau ni promesse).

Bien sûr, vous pouvez simplifier cela et commencer par obtenir le corps de chaque réponse juste après la promesse de récupération respective remplie:

Promise.all(urls.map(url =>
    fetch(url).then(resp => resp.text())
)).then(texts => {
    …
})
78
Bergi

Pour une raison quelconque, aucun des exemples de Bergi n'a fonctionné pour moi. Cela me donnerait simplement des résultats vides. Après un peu de débogage, il semble que la promesse reviendrait avant la fin de la récupération, d'où des résultats vides.

Cependant, Benjamin Gruenbaum avait une réponse ici plus tôt, mais l'a supprimée. Sa méthode a a fonctionné pour moi, je vais donc simplement la copier-coller ici, au cas où quelqu'un d'autre rencontrerait un problème avec la première solution ici.

var promises = urls.map(url => fetch(url).then(y => y.text()));
Promise.all(promises).then(results => {
    // do something with results.
});
18
peirix

Vous devriez utiliser map au lieu de forEach:

Promise.all(urls.map(url => fetch(url)))
.then(resp => Promise.all( resp.map(r => r.text()) ))
.then(result => {
    // ...
});
9
evgenAborigen