7

非常に長く、多くのタスクを実行するJavaScript関数があります。進行状況を、メッセージでSPAN要素の内容を更新してユーザーに報告したいと思います。関数コード全体にdocument.getElementById('spnProgress')。innerText=...ステートメントを追加してみました。

ただし、関数の実行中はUIが更新されないため、SPANに書き込まれた最後のメッセージのみが表示されます。これはあまり役に立ちません。

私の現在の解決策は、タスクをいくつかの関数に分割することです。各関数の最後にSPANメッセージを設定し、非常に短い遅延(たとえば、10ミリ秒)でwindow.setTimeout呼び出しを使用して次のメッセージを「トリガー」します。これにより制御が可能になり、ブラウザは次のステップを開始する前に、更新されたメッセージでSPANを再描画できます。

しかし、これは非常に厄介でコードに従うのが難しいと思います。もっと良い方法があるはずだと思います。誰か提案はありますか?関数のコンテキストを離れることなく、SPANを強制的に再描画する方法はありますか?

ありがとう

4

6 に答える 6

7

あなたがそれをしている方法は正しい方法です(現時点では、標準が出現して採用されるにつれてこれは変わるかもしれません[Andrew Aylettの答えを参照]が、まだしばらくはありません)。ブラウザがUIを更新できるようにするには、そのように譲歩する必要があります。私は、このように考えるほど、よりクリーンなものになることがわかりましたが、それを行うための最初のいくつかの刺し傷は、確かにかなり「厄介」でした。うまくいけば、あなたはそれに慣れているのと同じものを見つけるでしょう。

于 2010-04-07T12:28:30.130 に答える
3

ターゲットブラウザを制御できる場合は、HTML5ワーカースレッドを使用してバックグラウンドで作業を実行できる場合があります。

于 2010-04-07T12:33:05.403 に答える
2

長時間実行されているスクリプトがある場合、特定のブラウザでスクリプトタイムアウトメッセージが表示されることに注意する必要があります。したがって、実際にはタイマーを使用してこれを分割することが望ましいです。

そうは言っても、これを行うための本当に構造化された方法を探しているなら、私がスペルチェックプロジェクトのために書いたバックグラウンドタスクライブラリを見ることができます。これにより、タイマー上のデータの配列に対してmap/reduceを実装できます。

https://github.com/jameswestgate/taskjs

于 2010-04-07T12:32:14.130 に答える
0

これは、プロシージャを中断せずにプロシージャを中断できるかどうかを尋ねるようなものです。答えはいいえだ。ブラウザのレンダリングエンジンに制御を渡すには、setTimeout()またはsetInterval()を使用する必要があります。

setInterval()を使用すると、そのプロセスを実行でき、実行中の関数で外部変数を更新するだけで、setInterval()によって呼び出される関数によってポーリングされます。そうすれば、ループで呼び出すのではなく、1回だけ呼び出す必要があります。

于 2010-04-07T12:28:36.887 に答える
0

私が知っていることではありません。個々の関数が変数を共有できるようにコードを分割することができます。したがって、次のようになります。

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

runTasksWithProgressは少し注意が必要です。基本的に、最初のタスクを呼び出し、ステータスを更新してから、後続のタスクを実行するためのコールバックを設定します。

このアプローチは、痛みの一部を軽減する可能性があります。

于 2010-04-07T12:31:00.480 に答える
0

関数の作業がループで実行される場合、このようなものが機能する可能性があります。経過した時間をチェックし、1/2秒が経過した場合はプログレスバーを更新します。(この例はテストされていません。したがって、少し試してみる必要があるかもしれません。)

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);
于 2010-04-07T12:32:58.040 に答える