webentwicklung-frage-antwort-db.com.de

jQuery/Javascript - So warten Sie, bis das manipulierte DOM aktualisiert wurde, bevor Sie mit der Funktion fortfahren

Was ich versuche zu tun, ist ein einfaches div zu aktualisieren, um "Verarbeitung ..." zu sagen, bevor ein CPU-intensives Skript ausgeführt wird (es dauert 3-12 Sekunden, kein AJAX) und dann das div mit "Fertig!" " wenn fertig 

Was ich sehe, ist, dass das Div nie mit "Processing ..." aktualisiert wird. Wenn ich unmittelbar nach diesem Befehl einen Haltepunkt setze, wird der div-Text aktualisiert. Ich weiß, dass die Syntax korrekt ist. Gleiches Verhalten in IE9, FF6, Chrome13.

Selbst bei der Umgehung von jQuery und dem Verwenden von grundlegendem rohem Javascript sehe ich das gleiche Problem.

Sie würden denken, dass dies eine einfache Antwort hätte. Da jQuery .html () und .text () keinen Callback-Hook haben, ist dies jedoch keine Option. Es ist auch nicht animiert, es gibt also keine zu manipulierende .queue.

Sie können dies selbst testen, indem Sie den unten vorbereiteten Beispielcode verwenden, der sowohl die jQuery- als auch die Javascript-Implementierung mit einer 5-Sekunden-Hoch-CPU-Funktion zeigt. Der Code ist leicht zu befolgen. Wenn Sie auf die Schaltfläche oder den Link klicken, wird nie "Bearbeitung ..." angezeigt.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script type="text/javascript">
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    do {start = new Date();} while (end-start > 0);
    document.getElementById('msg').innerHTML = 'Finished JS';   
}
$(function() {
    $('button').click(function(){
        $('div').text('Processing JQ...');  
        start = new Date();
        end = addSecs(start,5);
        do {start = new Date();} while (end-start > 0);
        $('div').text('Finished JQ');   
    });
});
</script>
</head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>
23
pcormier

setzen Sie ihn auf "Verarbeitung", und führen Sie dann ein setTimeout aus, um zu verhindern, dass die CPU-intensive Task ausgeführt wird, bis das Div aktualisiert wurde.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></script>
<script>
function addSecs(d, s) {return new Date(d.valueOf()+s*1000);}
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    setTimeout(function(){
         start = new Date();
         end = addSecs(start,5);
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished Processing';   
    },10);
}
$(function() {
    $('button').click(doRun);
});    
</script>
    </head>
<body>
    <div id="msg">Not Started</div>
    <button>jQuery</button>
    <a href="#" onclick="doRun()">javascript</a>
</body>
</html>

sie können die setTimeout-Verzögerung nach Bedarf ändern. Für langsamere Maschinen/Browser muss diese möglicherweise größer sein.

Bearbeiten:

Sie können auch eine Warnung oder ein Bestätigungsdialogfeld verwenden, um die Aktualisierung der Seite zuzulassen.

document.getElementById('msg').innerHTML = 'Processing JS...';
if ( confirm( "This task may take several seconds. Do you wish to continue?" ) ) {
     // run code here
}
18
Kevin B

Sie haben eine Schleife, die für 5 Sekunden ausgeführt wird und den Webbrowser während dieser Zeit einfriert. Da der Webbrowser eingefroren ist, kann er nicht gerendert werden. Sie sollten setTimeout() anstelle einer Schleife verwenden, aber ich gehe davon aus, dass diese Schleife nur einen Ersatz für eine CPU-intensive Funktion darstellt, die eine Weile dauert. Sie können setTimeout verwenden, um dem Browser die Möglichkeit zu geben, zu rendern, bevor Sie Ihre Funktion ausführen:

jQuery:

$(function() {
    $('button').click(function(){
        (function(cont){
            $('div').text('Processing JQ...');  
            start = new Date();
            end = addSecs(start,5);
            setTimeout(cont, 1);
        })(function(){
            do {start = new Date();} while (end-start > 0);
            $('div').text('Finished JQ');   
        })
    });
});

Vanille JS:

document.getElementsByTagName('a')[0].onclick = function(){
    doRun(function(){
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished JS';   
    });
    return false;
};

function doRun(cont){
    document.getElementById('msg').innerHTML = 'Processing JS...';
    start = new Date();
    end = addSecs(start,5);
    setTimeout(cont, 1);
}

Denken Sie auch daran, immer alle Variablen mit dem Schlüsselwort var zu deklarieren und sie nicht dem globalen Gültigkeitsbereich auszusetzen. Hier ist ein JSFiddle:

http://jsfiddle.net/Paulpro/ypQ6m/

2
Paulpro

Ich musste warten, bis jQuery das DOM manipuliert} und dann die Änderungen erfassen (Formularfelder mehrmals in ein Formular laden und dann abschicken). Das DOM wuchs und das Einfügen dauerte länger und länger. Ich habe die Änderungen mit ajax gespeichert, damit der Benutzer dort fortfahren kann, wo er aufgehört hat.

Dies hat NICHT ARBEITEN wie beabsichtigt:

jQuery('.parentEl').prepend('<p>newContent</p>');
doSave(); // wrapping it into timeout was to short as well sometimes

Da jQuery-Funktionen wie .prepend() die Kette erst dann fortsetzen, wenn sie fertig sind, schien das Folgende den Trick zu tun :

jQuery('.parentEl').prepend('<p>newContent</p>').queue(function() {
  doSave();
});
0
BananaAcid

Ab 2019 verwendet man doublerequesAnimationFrame, um einen Frame zu überspringen, anstatt mit setTimeout eine Racebedingung zu erstellen.

....
function doRun() {
    document.getElementById('msg').innerHTML = 'Processing JS...';
    requestAnimationFrame(() =>
    requestAnimationFrame(function(){
         start = new Date();
         end = addSecs(start,5);
         do {start = new Date();} while (end-start > 0);
         document.getElementById('msg').innerHTML = 'Finished Processing';   
    }))
}
...
0
Estradiaz