Requete en boucle ou promise


#1

Bonjour,
Je debute un peu avec Javascript et j’aimerai votre avis sur mon idée. Mon objectif est de mettre à jour une base de façon sequentiel à partir d’une action utilisateur.

Je m’explique: j’ai un essemble de lien sous la forme

<ul id="list">
<li><a href="http://france24.com">France24</a></li>
<li><a href="http://eurosport.com">Eurosport</a></li>
</ul>
<button id="submit">Actualiser</button>

L’idée est que lorsque je clique sur le bouton Actualiser , ca recupere des contenus sur le premier lien et met à jour une base et des que c’est fait ca envoi un retour au frontend et fasse pareil pour le deuxieme lien.

J’ai fait un truc comme ceci en JS:

    let feeds = document.querySelectorAll('#list li > a')
    let counter = feeds.length
    let index = 0
    let data = []
    let feedUrl = feeds[index].getAttribute('href')

    let success = function (json) {
      index++

      if (index < counter) {
        feed = feeds[index].getAttribute('href')
        if (feed != null) {
          http(feedUrl, data, success, error)
        }
      }
    }

    let error = function (request, responseError) {
      console.warn('error', responseError)
    }

    http(feedUrl, data, success, error)

Et ce qu’une promise peut resoudre un truc comme ceci?


#2

Oui.

Une promesse est faites pour ça.

Cela te permet d’exécuter chaque mise à jour en parallèle, chacune n’attendant pas la fin de l’autre pour débuter. La seule certitude c’est qu’une fois toutes les actions en parallèle finies (tu n’as pas la main sur l’ordre) tu as de nouveau la main pour continuer (et dire par exemple à ton utilisateur que tout est ok).

Tu peux utiliser des promesses à l’intérieur de Promise.all pour ça par exemple.

Tu as un exemple de ça ici :

Promise.all([
			System.import('views-models/' + name + '.js'),
			System.import('variations/' + name + '.json!json'),
			System.import('views-models/' + name + '.htm!text')
		]).then(function (files) {
			model = files[0];
			specific = files[1];
			template = files[2];
			options = {
				dirty: false
			};

			resolve(model(specific, template, mixin(!webconfig.routes[key]._children), options));
		});

Ici je charge trois fichier, peut importe l’ordre, une fois chargés, je compile le tout. Chaque System.import retourne une promesse. Tu peux donc utiliser tout ce qui retourne une promesse ou une promesse elle-même à la place.

En espérant t’avoir aidé.


#3

@Haeresis a bien expliqué la résolution. Je souhaite juste apporter une précision sur Promise.all : Si au moins une requête échoue, tu ne passeras pas dans le then. Si tu souhaites que la mise à jour des liens soit indépendante pour chacun des liens, crées des promises indépendantes.


#4

Je suis un peu perdu. Je ne suis pas encore très avancé donc par rapport à mon exemple ?


#5

Je ne sais pas comment fonctionne la fonction http. Mais il faut la transformer en promise (si non fait).

const promiseHttp = new Promise((resolve, reject) => http(feedUrl, data, resolve, reject))

Ensuite, tu appelles then et catch en lieu et place de success et error.
Avec ce qu’a dit @Haeresis, je pense que tu pourras trouver le reste de la logique pour ton cas.


#6

http est juste une function pour XMLHttpRequest


#7

En espérant que cela puisse t’aider @captainkidd

Documentation

Tu trouveras plus d’informations à propos des promesses :

et de Promise.all ici :

Problème du Promise.all qui s’arrête des le reject.

Quand tu crées une promesse, tu peux te servir d’une callback et toi même définir dans quel cas la promesse est résolue ou rejetée en executant au choix resolve() ou reject(). Tu peux donc décider de toujours resolve la promesse, même quand l’appel à l’intérieur n’a pas marché.

Dans le retour de Promise.all qui passera dans le then car tu as toi même indiqué qu’en qu’a d’échec de ta fonction http() la promesse est résolue, et tu afficheras les messages correspondant aux entrées qui n’ont pas été mise à jour (celle ayant été mise à jour l’ayant été fait lors de l’exécution de la Promise dédiée).

Démo

<!DOCTYPE html>
<html lang="fr">
    <head>
        <meta charset="UTF-8">
        <title>Test</title>
    </head>
    <body>
        <ul id="list">
            <li><a href="http://localhost/test2.json">France24</a></li>
            <li><a href="http://badurl/test3.json">Eurosport</a></li>
        </ul>
        <script>
            var http = function (url, value) {
                    return new Promise(function (resolve, reject) {
                        var request = new XMLHttpRequest();

                        request.addEventListener("load", function () {
                            if (request.status < 200 && request.status >= 400) {
                                reject(new Error("We reached our target server, but it returned an error."));
                            }

                            resolve(request.responseText);
                        });

                        request.addEventListener("error", function () {
                            reject(new Error("There was a connection error of some sort."));
                        });

                        request.open("GET", url, true);
                        request.send(value);
                    });
                },
                feeds = document.querySelectorAll('#list li > a'),
                promises = [];

            Array.prototype.forEach.call(feeds, function (entry) {
                var url = entry.getAttribute('href'),
                    promise = new Promise(function (resolve) {
                        http(url, {})
                        .then(function (value) {

                            // Ici on dit OK des que c'est traité
                            console.log("Asap OK", value);

                            resolve(value);
                        })
                        .catch(function (reason) {

                            console.log("Asap NOK", reason);

                            // Ici on dit NOK dès que c'est foiré
                            resolve(reason);
                        });
                    });

                promises.push(promise);
            });

            Promise.all(promises).then(function (values) {
                values.forEach(function (value) {
                    if (value instanceof Error) {
                        // Ici on dit tout ce qui a foiré
                        console.log("End NOK", value);
                    } else {
                        // Ici on dit tout ce qui a été OK
                        console.log("End Ok", value);
                    }
                });
            });
        </script>
    </body>
</html>