2
votes

La page HTML ne se met pas à jour pendant l'exécution d'une fonction javascript

Chrome, FF. Opera et probablement d'autres navigateurs affichent uniquement le numéro 100000 à la fin du processus, mais je veux voir affiché dans la séquence 1..2..3..4 ... 100000. Ce code ne fonctionne pas bien:

<html>
<head>
</head>
<body>

<button type="button" onclick="executeMultiLongProcess();">Launch and monitoring long processes!</button>
<p id="statusOfProcess"></p>

<script>
var el = document.getElementById('statusOfProcess'); 

function executeMultiLongProcess() {                   
    processPart1();
}
function processPart1() {
    el.innerHTML = "Start Part 1"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part 1";        
        window.setTimeout(processPart2, 0);     
    },10);
}
function processPart2() {
    el.innerHTML = "Start Part 2"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part 2";
        window.setTimeout(processPartN, 0);
    },10);
}
function processPartN() {
    el.innerHTML = "Start Part N"; 
    setTimeout(function(){ 
        for(var nn=0;nn<=100000000;nn++){  //.. 
        }
        el.innerHTML = "End Part N"; 
    },10);
}
</script>
</body>
</html>

window.setTimeout n'est pas possible en utilisant quand vous ne connaissez pas le temps d'exécution d'un processus donné et même en changeant les attributs de l'objet div principal (visibilité par exemple) ne fonctionne pas pour moi.

Merci du tout.


MISE À JOUR

Voici une solution partielle.

Permet de visualiser l'état d'un long processus, pour l'instant, malheureusement seulement le début et la fin du (unique) processus.

<html>
<head>
</head>
<body>

<button type="button" onclick="showSequence();">Show the numbers one at a time!</button>
<p id="herethenumbers">00</p>

<script>
function showSequence() {                   
    el = document.getElementById('herethenumbers'); 
    for(var nn=0;nn<=100000;nn++){  
        el.innerHTML = nn;      
    }
}
</script>
</body>
</html>


6 commentaires

C'est comme ça que les choses fonctionnent. Il n'y a aucune raison pour que le navigateur mette à jour la vue pendant l'exécution du code, donc ce n'est pas le cas.


Une raison simple est de mettre à jour l'utilisateur sur l'état du processus


@Pointy essayait de souligner que lorsque le navigateur exécute le code, il a des règles pour mettre à jour l'écran. Si vous voulez que le navigateur se comporte d'une manière particulière, vous devez comprendre ces règles et comment les manipuler. Il n'y a pas de place dans cette boucle for où le navigateur a la possibilité de redessiner l'écran ou où il lui est demandé de redessiner l'écran.


@Jason Alle, j'ai essayé de le faire, en utilisant par exemple: el.style.visibility = "hidden"; el.innerHTML = nn; el.style.visibility = "visible"; mais le navigateur semble ignorer tout type de changement d'état


Peut-être que je manque quelque chose, mais pourquoi pas 'el.innerHTML = el.innerHTML + nn +'
';' travail? Cela devrait montrer le décompte dans l'ordre. Remplacez "
" par "," si vous voulez tous les nombres sur 1 ligne.


@CharlesEF - mon objectif est de montrer l'avancement d'une fonction javascript qui peut prendre quelques minutes, par exemple afficher un compteur ou une barre de progression, le navigateur jusqu'à ce que le focus soit à nouveau ne montre aucune variation des éléments à l'écran


4 Réponses :


1
votes

Utilisez window.setInterval :

<button type="button" onclick="showSequence();">
   Show the numbers one at a time!
</button>
<p id="herethenumbers">00</p>
function showSequence() {                   
    var el = document.getElementById('herethenumbers');
    var nn = 0;
    var timerId = setInterval(countTo100, 80); 
    function countTo100(){  
        el.innerHTML = nn;
        nn++;
        if (nn>100) clearTimeout(timerId);      
    }
}

Mise à jour

le scénario est un peu différent. Vous avez un processus javascriot qui démarre et se termine sans interruption, il peut fonctionner plusieurs minutes en attendant, à l'intérieur, il doit afficher à l'écran l'état de sa progression.

JavaScript est monothread dans toutes les implémentations de navigateur modernes 1 . Pratiquement tout le code javascript existant (au moins tout le code javascript non trivial) serait cassé si le moteur javascript d'un navigateur l'exécutait de manière asynchrone.

Pensez à utiliser Web Workers , une API explicite et standardisée pour le code javascript multi-thread.

Web Workers est un moyen simple pour le contenu Web de exécuter des scripts dans les threads d'arrière-plan. Le thread de travail peut effectuer des tâches sans interférer avec l'interface utilisateur. De plus, ils peuvent effectuer des E / S à l'aide de XMLHttpRequest (bien que les attributs responseXML et channel soient toujours nuls). Une fois créé, un worker peut envoyer des messages au code JavaScript qui l'a créé en publiant des messages dans un gestionnaire d'événements spécifié par ce code (et vice versa).

Pour plus d'informations, voir Référence de l'API Web MDN - Web Workers .


2 commentaires

Merci georgeawg, cela fonctionne mais le scénario est un peu différent. Vous disposez d'un processus javascriot qui démarre et se termine sans interruption, il peut fonctionner plusieurs minutes en attendant, à l'intérieur de celui-ci, il doit afficher à l'écran l'état de sa progression.


WebWorkers est très intéressant, mais comme le dit la documentation, "vous ne pouvez pas manipuler directement le DOM de l'intérieur vers le worker, ou utiliser certaines méthodes et propriétés par défaut de la fenêtre". Cette excellente solution ne peut être utilisée que dans des cas spécifiques



0
votes

Exemple de code ci-dessous en utilisant setTimeout code > , ne compte que jusqu'à 100 pour l'échantillon.

Vous voudrez peut-être consulter Différence entre setTimeout avec et sans guillemets et parenthèses

Et puis il y a aussi: 'setInterval' vs 'setTimeout'

<button type="button" id="start">Show the numbers one at a time!</button>
<p id="herethenumbers">00</p>
var delayId = null, frameTime = 25, countTo = 100, el, nn = 0;
function increment(e) {
  if (delayId) {
    window.clearTimeout(delayId);
  }
  el.textContent = nn++;
  if (nn <= countTo) {
    delayId = window.setTimeout(increment,frameTime);
  }
}
window.onload = function() {
    el = document.getElementById('herethenumbers');
    var b = document.getElementById('start');
    b.addEventListener("click",increment,false);
}


0 commentaires


0
votes

Utiliser requestAnimationFrame comme suggéré par Jan-Luca Klees est la solution à mon problème, voici un exemple simple d'utilisation de requestAnimationFrame. Vous permet d'exécuter un ou plusieurs processus de longue durée avec l'interaction avec des objets à l'écran (une popup par exemple ou d'autres), requestAnimationFrame indique au navigateur que vous souhaitez exécuter une animation et que vous souhaitez que le navigateur appelle une fonction spécifique pour mettre à jour un animation.

<html>
<head>
</head>
<body>

<button type="button" onclick="startProcesses();">Start long duration process!</button>
<p id="status">Waiting to start processes</p>

<script>
el = document.getElementById('status');

var current_process = 1;
var total_process = 2; 
var startEnd = 'S';

function startProcesses() {                   

    function step(timestamp) {
        if(current_process==1 && startEnd=='E') res = process1();
        if(current_process==2 && startEnd=='E') res = process2();       
        //..n processes

        if(startEnd=='S') el.innerHTML = "Process #"+current_process+" started..";
        if(startEnd=='E') el.innerHTML = "Process #"+current_process+" "+res;

        if(startEnd=='S' || current_process<total_process) {
            if(startEnd=='E') current_process++;
            startEnd = (startEnd=='S'?'E':'S'); 
            window.requestAnimationFrame(step);     
        }else{
            el.innerHTML = "Process #"+current_process+" "+res;
        }
    }
    window.requestAnimationFrame(step);
}

function process1() {                
    for(var nn=0;nn<=10000;nn++){  
        console.log(nn);
    }
    return "Success!"; //or Fail! if something went wrong
}
function process2() {                                
    for(var nn=0;nn<=10000;nn++){  
        console.log(nn);
    }
    return "Success!"; //or Fail! if something went wrong
}
</script>
</body>
</html>


0 commentaires