jquery/javascript-機能を進める前に操作されたDOMが更新するのを待つ方法

StackOverflow https://stackoverflow.com/questions/7342084

質問

私がやろうとしているのは、CPU集約型のスクリプトを実行する前に「処理...」と言うように簡単なDivを更新することです(実行するには3〜12秒かかり、AJAXはありません)。 「それが終わったら。

私が見ているのは、divが「処理...」で更新されることはないということです。そのコマンドの直後にブレークポイントを設定すると、Divテキストが更新されるため、構文が正しいことがわかります。 IE9、FF6、Chrome13で同じ動作。

jQueryをバイパスして基本的なRAW JavaScriptを使用している場合でも、同じ問題が見られます。

これには簡単な答えがあると思うでしょう。ただし、jQuery .html()と.text()にはコールバックフックがないため、オプションではありません。また、アニメーション化されていないため、操作する必要はありません。

5秒のハイCPU関数を備えたJQueryとJavaScriptの両方の実装を示す、以下で準備したサンプルコードを使用して、これをテストできます。コードは簡単に従うことができます。ボタンまたはリンクのいずれかをクリックすると、「処理...」が表示されません。

<!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>
役に立ちましたか?

解決

処理に設定してから、CPU集中タスクが実行されないようにするためにSetimeoutを実行します。

<!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>

必要に応じてSettimeout Delayを変更できます。より遅いマシン/ブラウザの場合は、より大きくする必要がある場合があります。

編集:

また、アラートまたは確認ダイアログを使用して、ページの時間を更新できるようにすることもできます。

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

他のヒント

5秒間実行され、その間にWebブラウザーをフリーズするループがあります。 Webブラウザは凍結されているため、レンダリングはできません。使用する必要があります setTimeout() ループの代わりに、しかし、ループはしばらくかかるCPU集中関数の単なる代替品であると仮定していますか? SettimeOutを使用して、関数を実行する前にブラウザにレンダリングする機会を提供できます。

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');   
        })
    });
});

バニラ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);
}

また、VARキーワードを使用して常にすべての変数を宣言し、それらをグローバルスコープにさらすことを避けることを忘れないでください。これがjsfiddleです:

http://jsfiddle.net/paulpro/ypq6m/

そうしなければならなかった jQueryがDOMを操作するのを待ちます 次に、変更をグラップします(フォームフィールドを複数回フォームに入れてから送信します)。 DOMが成長し、挿入はより長くかかりました。 Ajaxを使用して変更を保存して、ユーザーが中断したところから続けることができるようにしました。

これはそうしました うまくいかない 意図した通り:

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

jqueryは次のように機能するためです .prepend() 完了した場合にのみチェーンを続行してください、次のように見えました トリックをしてください:

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

2019年の時点で使用しています ダブル requesAnimationFrame Settimeoutを使用してレース条件を作成する代わりにフレームをスキップする。

....
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';   
    }))
}
...
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top