11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour,
je réalise une interface web pour des mesures effectuées par un ESP32 qui embarque le serveur web et la partie mesure physique. À partir de ces mesures je trace un graphique (en utilisant chart.js) et ça marche... pas trop mal.

J'ai ceci en fin de page web :

<script>
    document.addEventListener("DOMContentLoaded", function() {
        fetch('data.json')
            .then(response => response.text())
            .then(data => {
                const donnees = JSON.parse(data);
                new Chart(document.getElementById("graphique"), {
                    type: 'line',
                    data: {
                        datasets: [{
                            data: donnees,
                            borderColor: "#555",
                            fill: false
                        }]
                    },
                    options: {
// couic toutes les options, OSEF...
                });
            })
            .catch(error => console.error('Erreur lors du chargement des données:', error));
    });
</script>


De temps en temps (plutôt quand il y a pas mal de données) le fichier data.json est incomplet et il y a une erreur qui apparaît. Normal le fichier termine par quelque chose comme

,{"x":1564,"y":23.66},


au lieu de finir proprement avec le ] :

,{"x":1689,"y":24.81},{"x":1690,"y":24.71}]


Ça vient peut-être des délais liés à la génération du json, l'ESP32 est un peu à la peine et je vais essayer d'optimiser cette partie.

Mais ma question porte sur un autre aspect : quasiment toujours un F5 règle le problème et le graphique apparaît proprement.

Est-il possible en JavaScript (langage pour lequel je suis un peu neuneu !) de « rejouer » toute la partie
document.addEventListener("DOMContentLoaded", function() {}
en cas d'erreur.


Merci d'avance
Bonjour Christian,

Dites donc mais il est passionnant votre projet !

Lorsque vous dites "il y a une erreur qui apparaît", vous faites référence à quelle erreur ? Car si je comprends bien catch() ne renvoie aucune erreur, et then() vous renvoie bien un code JSON généré, bien qu'incomplet.

Tout se passe comme si l'ESP32 n'avait pas le temps de produire toutes les données en temps et en heure et, si la problématique est bien celle-ci, je ne suis pas sûr que le script puisse être en mesure de le détecter.

Par contre on pourrait vérifier la validité du JSON et, si pas valide, relancer le script.
Olivier C a écrit :
je ne suis pas sûr que le script puisse être en mesure de le détecter.

Quoi que... essayez avec ce code réécrit avec try/catch et async/await :
document.addEventListener("DOMContentLoaded", async function() {
    try {
        const response = await fetch('data.json');
        const data = await response.text();
        const donnees = JSON.parse(data);
        
        new Chart(document.getElementById("graphique"), {
            type: 'line',
            data: {
                datasets: [{
                    data: donnees,
                    borderColor: "#555",
                    fill: false
                }]
            },
            options: {
// couic toutes les options, OSEF...
            }
        });
    } catch (error) {
        console.error('Erreur lors du chargement des données:', error);
    }
});

Dans le code original les erreurs lors du téléchargement des données ou du parsing du JSON étaient capturées uniquement par le catch après la chaîne de promesses .then(). Si une erreur se produisait lors du traitement, par exemple, lors du parsing JSON (JSON.parse), l'erreur était sensée être gérée correctement ***. Cependant, il pouvait y avoir un kouac si un problème survenait plus tôt, par exemple pendant l'extraction du texte ou lors de la réponse initiale de fetch, comme il semble que ce soit le cas ici.

___
*** quand même, déjà à ce niveau j'ai du mal à comprendre que le JSON généré ne soit pas valide, je vais faire un code alternatif dans un post suivant qui ajoute une vérification de l'intégrité du JSON généré.
Modifié par Olivier C (21 Aug 2024 - 04:20)
Si le code précédent n'est pas efficient, voici un update vérifiant l'intégrité du JSON généré :
document.addEventListener("DOMContentLoaded", async function() {
    const retryDelay = 2000; // Délai en millisecondes avant de réessayer
    const maxRetries = 3; // Nombre maximum de tentatives
    let attempts = 0;

    async function loadData() {
        try {
            const response = await fetch('data.json');
            const data = await response.text();
            const donnees = JSON.parse(data);

            // Vérification de la validité du JSON
            if (!Array.isArray(donnees) || donnees.length === 0) {
                throw new Error("Données JSON invalides : le tableau est vide ou non valide.");
            }

            // Optionnel: Vérification des éléments individuels. Pas forcément utile dans votre cas, à voir...
            donnees.forEach((element, index) => {
                if (typeof element !== 'object' || element === null || !('x' in element) || !('y' in element)) {
                    throw new Error(`Donnée JSON invalide à l'index ${index} : chaque élément doit être un objet avec les propriétés 'x' et 'y'.`);
                }
            });

            new Chart(document.getElementById("graphique"), {
                type: 'line',
                data: {
                    datasets: [{
                        data: donnees,
                        borderColor: "#555",
                        fill: false
                    }]
                },
                options: {
                    // couic toutes les options, OSEF...
                }
            });

        } catch (error) {
            console.error('Erreur lors du chargement des données:', error);
            attempts++;
            if (attempts < maxRetries) {
                console.log(`Nouvelle tentative de récupération des données dans ${retryDelay / 1000} secondes... (Tentative ${attempts}/${maxRetries})`);
                setTimeout(loadData, retryDelay);
            } else {
                console.error('Nombre maximum de tentatives atteint. Échec du chargement des données.');
            }
        }
    }

    loadData(); // Première tentative de chargement des données
});

Le code se complexifie, j'espère qu'il reste lisible pour autant.
Modifié par Olivier C (21 Aug 2024 - 04:42)
Olivier C a écrit :
Dites donc mais il est passionnant votre projet !


Merci Smiley cligne

Olivier C a écrit :
vous faites référence à quelle erreur ? Car si je comprends bien catch() ne renvoie aucune erreur, et then() vous renvoie bien un code JSON généré, bien qu'incomplet.


C'est le parse() qui génère une erreur.

J'ai trouvé/bricolé une solution qui à l'air fonctionnelle et que je poste tout à l'heure...
Modifié par ChristianW (21 Aug 2024 - 08:55)
<script>
document.addEventListener("DOMContentLoaded", function() {
    const maxEssais = 3;  
    let   nbrEssais = 0; 

    function fetchData() {
        fetch('data.json')
            .then(response => response.text())
            .then(data => {
                try {
                    const donnees = JSON.parse(data);
                    new Chart(document.getElementById("graphique"), {
                        type: 'line',
                        data: {
                            datasets: [{
                                data: donnees,
                                borderColor: "#555",
                                fill: false
                            }]
                        },
                        options: {
/ couic toutes les options, OSEF...
                        }
                    });
                } catch (error) {
                    if (nbrEssais < maxEssais) {
                        nbrEssais++;
                        console.warn(`Erreur lors de l'analyse JSON (${nbrEssais}/${maxEssais})...`);
                        fetchData();  // Recharge
                    } else {
                        console.error('Trop d\'erreurs', error);
                    }
                }
            })
            .catch(error => console.error('Erreur lors du chargement des données:', error));
    }

    fetchData();  // premiere tentative
});
</script>


Ça fait manifestement ce que je veux mais, comme je suis un peu neuneu en JS, je suis preneur de toute critique/commentaire
Oui ça marche aussi, mais :
- le couple .then()/.catch() c'est l'ancienne syntaxe
- l'ensemble try/catch + async/await est la nouvelle syntaxe
Dans votre exemple vous mélangez les deux styles de codage. Pas grave en soit, mais c'est mieux de se tenir à l'une ou à l'autre, ça rend le code plus lisible (et ça évite des confusions : par exemple vous avez ici deux systèmes de traitement de l'erreur traitant chacun une partie de ces erreurs).

Bien sûr je conseillerais la méthode la plus récente. Je commente quelques lignes de mon code posté plus haut :
async function loadData() { // On déclare la fonction comme asynchrone.
    try { // Ici on crée un block qui permettra de traiter les erreurs le cas échéant avec un "catch" un peu plus loin.
        const response = await fetch('data.json'); // étant donné que la fonction est asynchrone, la mention "await" demande d'attendre la fin de l'instruction qui suit avant de passer à la suite, sinon tout sera fait en parallèle, ce qui ne convient pas ici.
        const data = await response.text(); // idem.

Modifié par Olivier C (21 Aug 2024 - 21:12)
Olivier C a écrit :

Dans votre exemple vous mélangez les deux styles de codage. Pas grave en soit, mais c'est mieux de se tenir à l'une ou à l'autre, ça rend le code plus lisible (et ça évite des confusions : par exemple vous avez ici deux systèmes de traitement de l'erreur traitant chacun une partie de ces erreurs).


Merci pour ce retour, je vais lire ça à tête reposée. J'avoue sans complexe ma grande incompétence en JS. Je code en prenant des bout de code de-ci de-là, en essayant de voir à peu près ce qu'ils font, adaptant jusqu'à ce que ça tombe en marche.

Pas terrible du tout, je le sais bien mais c'était un peu dans l'urgence. Faut que je m'y mette plus sérieusement !
ChristianW a écrit :
Je code en prenant des bout de code de-ci de-là, en essayant de voir à peu près ce qu'ils font, adaptant jusqu'à ce que ça tombe en marche.
Pas terrible du tout...

Au contraire c'est plutôt pas mal. Personne n'apprend à coder en commençant par lire de la documentation, on commence par vouloir résoudre une problématique en cherchant à obtenir quelque chose qui fonctionne le plus rapidement possible, donc éventuellement en s'inspirant d'autres codes ; c'est ensuite seulement que l'on cherche à s'améliorer, en lisant de la documentation et d'autres ressources plus à distance de nos préoccupations du moment.