2015-07-29 1 views
18

Si j'ai un tableau de urls:Comment puis-je récupérer un tableau d'URL avec Promise.all?

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'ai essayé d'apprendre à faire avec fetch, qui bien sûr renvoie Promise s.

Certaines choses que j'ai essayé que ne le font pas travail:

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 juste, et en tout cas, il ne fonctionne pas - je ne finis pas avec un array ['un', 'deux', 'trois'].

Est-ce que la Promise.all utilise la bonne approche ici?

+0

qui ressemble à une erreur de bracketing. Aviez-vous vraiment l'intention d'appeler '.then' sur la valeur de retour de' .forEach (...) ', ou plutôt sur' ... .text() '? – Bergi

+0

Où regardez-vous/notez 'texts' et observez-le pour être encore vide? – Bergi

Répondre

39

Oui, Promise.all est la bonne approche, mais vous devez en fait deux fois si vous voulez d'abord fetch tous les urls et obtenir tous les text s d'eux (qui sont à nouveau promesses pour le corps de la réponse). Donc, vous auriez besoin de faire

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

Votre code actuel ne fonctionne pas parce que rien forEach rendement (ni un tableau, ni une promesse).

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

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

Adressage de quelque chose que j'ai senti dans la question: Vous ne pouvez pas "extraire" les résultats d'une variable externe en raison de la façon dont async fonctionne en JavaScript, mais vous pouvez utiliser des générateurs ou async/await pour le simuler. Voir [cette réponse] (http://stackoverflow.com/a/30180679/1348195) pour un guide complet sur l'asynchronisme dans JS. –

+0

cela semble incroyable! mais je ne peux pas envelopper ma tête :(javascript est une langue étrange – yota

12

Pour une raison quelconque, ni des exemples de bergi ont travaillé pour moi. Cela me donnerait simplement des résultats vides. Après un débogage, il semble que la promesse reviendrait avant que le fetch soit terminé, d'où les résultats vides. Cependant, Benjamin Gruenbaum avait une réponse ici plus tôt, mais l'a supprimée. Sa méthode a fait travail pour moi, donc je vais simplement copier-coller ici, comme une alternative au cas où quelqu'un d'autre rencontre des problèmes 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. 
}); 
3

Vous devez utiliser map au lieu de forEach:

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