2010-04-07 13 views
7

Ich habe eine JavaScript-Funktion, die ziemlich lang ist und eine Reihe von Aufgaben ausführt, ich möchte den Fortschritt berichten, indem ich den Inhalt eines SPAN-Elements mit einer Nachricht aktualisieren, wie ich gehe. Ich habe versucht, document.getElementById ('spnProgress'). InnerText = ... Anweisungen im Funktionscode hinzuzufügen.Wie kann ich den Fortschritt einer JavaScript-Funktion melden?

Während die Funktion ausgeführt wird, wird die Benutzeroberfläche jedoch nicht aktualisiert und Sie sehen immer nur die letzte Nachricht, die in den SPAN geschrieben wurde, was nicht sehr hilfreich ist.

Meine aktuelle Lösung ist die Aufgabe in eine Reihe von Funktionen zu brechen, am Ende von jedem ich die SPAN-Nachricht einstellen und dann "triggern" die nächste mit einem window.setTimeout Anruf mit einer sehr kurzen Verzögerung (sagen wir 10ms). Dies führt zu Kontrolle und erlaubt dem Browser, den SPAN mit der aktualisierten Nachricht neu zu streichen, bevor der nächste Schritt gestartet wird.

Allerdings finde ich das sehr chaotisch und schwierig, dem Code zu folgen, ich denke, dass es einen besseren Weg geben muss. Hat jemand irgendwelche Vorschläge? Gibt es eine Möglichkeit, das SPAN neu zu streichen, ohne den Kontext der Funktion verlassen zu müssen?

Dank

Antwort

7

Die Art und Weise Sie es tun ist der richtige Weg (im Moment, kann dies als Standards ändern entstehen und angenommen werden [siehe Andrew Aylett des answer], aber nicht für eine Weile noch) nicht. Sie müssen so nachgeben, damit der Browser seine UI-Updates durchführen kann. Ich habe festgestellt, dass je mehr ich denke, desto sauberer wird es, aber meine ersten Schritte waren ziemlich "chaotisch". Hoffentlich findest du dasselbe, an das du dich gewöhnt hast.

+0

Dies ist die richtige Wahl. – Kangkan

0

Das ist wie die Frage, ob es möglich ist, eine Prozedur zu unterbrechen, ohne eine Prozedur zu unterbrechen. Die Antwort ist nein. Sie müssen setTimeout() oder setInterval() verwenden, um die Steuerung an die Rendering-Engine des Browsers zu übergeben.

Wenn Sie setInterval() verwenden, können Sie diesen Prozess in Gang setzen und in Ihrer ausführenden Funktion einfach eine externe Variable aktualisieren, die von der von setInterval() aufgerufenen Funktion abgefragt wird. Auf diese Weise müssen Sie nur einen Anruf tätigen, anstatt sie in einer Schleife auszuführen.

0

Nicht, dass ich weiß.

var a = some_local_state(); 
runTasksWithProgress([ 
    function() { 
     do_some_work(a); 
     a = a + 1; 
    }, 
    function() { 
     do_some_other_work(a); 
     a = a * 2; 
    }, 
    ... 
    ]); 

runTasksWithProgress ist ein bisschen schwierig: Sie könnten Ihren Code so, dass die einzelnen Funktionen können Variablen teilen, so brechen. Sie würden im Grunde die erste Aufgabe aufrufen, den Status aktualisieren und dann einen Rückruf einrichten, um nachfolgende Aufgaben auszuführen.

Dieser Ansatz könnte einige der Schmerzen lindern.

2

Sie müssen beachten, dass Sie in bestimmten Browsern eine Skript-Timeout-Nachricht erhalten, wenn Sie ein Skript mit langer Laufzeit haben. Es ist also eigentlich wünschenswert, dies mit einem Timer zu teilen.

Nachdem Sie dies gesagt haben, wenn Sie nach einem wirklich strukturierten Weg suchen, dies zu tun, dann können Sie sich eine Hintergrund-Task-Bibliothek ansehen, die ich für ein Rechtschreibprojekt geschrieben habe. Es ermöglicht Ihnen die Implementierung von map/reduce gegen Datenfelder auf einem Timer.

https://github.com/jameswestgate/taskjs

+0

+1 guter Punkt über das Skript-Timeout. –

0

So etwas wie dies funktionieren kann, wenn die Arbeit Ihre Funktion ist in einer Schleife durchgeführt wird. Es überprüft die verstrichene Zeit und aktualisiert den Fortschrittsbalken, wenn 1/2 Sekunde vergangen ist. (Das Beispiel ist ungetestet. Sie müssen also vielleicht ein bisschen damit spielen.

)
var start; 
function longRunning(lastState){ 
    start = (new Date); 
    for(var i = lastState; i < 1e6 /*= 1000000 iterations */; ++i){ 
     if((new Date)-start<500){ 
      // do your stuff; 
     } 
     else{ 
      // call a function to update the progress bar 
      updateProgressBar(); 
      // continue the loop... 
      setTimeout(function(){longRunning(i);},13); 
      break; 
     } 
    } 

} 
longRunning(0); 
3

Wenn Sie die Kontrolle über den Ziel-Browser haben, können Sie in der Lage sein, ein HTML5 worker thread zu verwenden, um die Arbeit im Hintergrund zu tun.