J'ai un tableau d'URL que j'aimerais exécuter une requête fetch ()
à:
const urls = [ 'https://dewnuf111111.com/configuration', 'https://dewnuf222222.com/configuration', 'https://bcsmania.co.uk/test.json' ]; let obj = {a: 'test'}; let counter = 0; function ajax(url) { // Check for for last URL in the array if (counter < urls.length) { return fetch(url) .then(response => { // Combine objects obj = Object.assign(obj, response.json()); console.log(urls[counter], obj); return Promise.resolve(obj); }).catch(error => { counter++; // Fetch next URL ajax(urls[counter]); }); } } function getConfigurations() { return ajax(urls[counter]); } getConfigurations().then((configurations) => { console.log('DONE', configurations); });
Si la récupération détecte une erreur (par exemple, le le site n'existe pas, erreur interne, etc.), j'aimerais qu'il tente la prochaine URL, j'ai donc ajouté un incrémenteur.
Une fois qu'il a atteint une URL de travail et fait une demande avec succès, il devrait alors simplement console.log ('DONE')
, mais je n'arrive pas à le faire fonctionner.
Voici le code que j'ai écrit jusqu'à présent:
const urls = [ 'https://dewnuf111111.com/configuration', 'https://dewnuf222222.com/configuration', 'https://bcsmania.co.uk/test.json' ];
Voici un JSFiddle pour voir un aperçu.
Quelqu'un peut-il me dire où je pourrais me tromper?
Dois-je rendre la fonction asynchrone
puis attendre
le résultat?
3 Réponses :
Vous devez renvoyer la promesse dans votre capture afin de pouvoir également la chaîner:
.catch(error => { counter++; // return Fetch next URL return ajax(urls[counter]); });
Ici, vous mélangez du code asynchrone avec du code de synchronisation. Puisque votre boucle est de nature synchronisée, elle n'attend pas le résultat et une fois le code résolu, elle imprime TERMINÉ. La solution la plus simple, vous pouvez utiliser async-await dans l'URL de la boucle. J'ai donné un exemple ci-dessous. Veuillez vérifier.
https://jsfiddle.net/gof91e6v/
const urls = [ "https://dewnuf111111.com/configuration", "https://dewnuf222222.com/configuration", "https://bcsmania.co.uk/test.json" ]; let obj = { a: "test" }; async function getConfigurations(urls) { let result = null; if (counter < urls.length) { for (let count = 0, len = urls.length; count < len; count++) { try { result = await fetch(urls[count]); } catch (e) {} if (result) break; } } return result; } getConfigurations(urls).then(configurations => { console.log("DONE", configurations); });
Je chercherais à séparer la récupération d'une liste d'URL de la façon dont vous la gérez (par exemple votre appel à Object.assign
.)
Dans cette version, fetchFirstWorking code > accepte une liste d'urls et répond avec une promesse qui sera résolue avec le résultat de la récupération de la première URL en direct. Notez qu'il utilise la récursivité plutôt qu'un compteur, donc la gestion des états est réduite au minimum.
getConfiguration
contient la logique métier.
const fetchFirstWorking = ( [url, ...urls], conf ) => url ? fetch (url, conf) .catch ( _ => fetchFirstWorking(urls) ) : Promise .reject ('no urls could be loaded') const getConfigurations = (urls) => fetchFirstWorking(urls) .then ( res => res .json () ) .then ( res => Object .assign ({a: 'test'}, res) ) const urls = [ 'https://dewnuf111111.com/configuration', 'https://dewnuf222222.com/configuration', 'https://dewnuf333333.com/configuration', ] getConfigurations (urls) .then(console.log) .catch(console.warn)
Si vous remplacez la dernière URL par un autre factice, vous la verrez générer l'avertissement de la console à la place:
const fetchFirstWorking = ( [url, ...urls], conf ) => url ? fetch (url, conf) .catch ( _ => fetchFirstWorking (urls) ) : Promise .reject ('no urls could be loaded') const getConfigurations = (urls) => fetchFirstWorking(urls) .then ( res => res .json () ) .then ( res => Object .assign ({a: 'test'}, res) ) const urls = [ 'https://dewnuf111111.com/configuration', 'https://dewnuf222222.com/configuration', 'https://bcsmania.co.uk/test.json' ] getConfigurations (urls) .then(console.log) .catch(console.warn)
Copie possible de manière propre d'attendre le premier vrai renvoyé par Promesse
Je pense que ce candidat en double est peut-être ce que vous voulez. Je ne sais pas si vous voulez que ceux-ci soient essayés séquentiellement et un à la fois (au lieu de tous en même temps).
return ajax (urls [compteur]);
@Kaiido - Ughr merci beaucoup. Je ne peux pas croire que je n'ai pas vu ça. Si vous souhaitez ajouter votre solution en tant que réponse ci-dessous, je l'accepterai avec plaisir.
Je cherchais une dupe (il doit y en avoir déjà une) mais je ne peux pas la trouver pour le moment, alors j'ai posté une CW.