1

アクティビティ インジケーターを開始するメソッドと、特定のインジケーターを停止する別のメソッドを作成しました。次に、時間のかかるタスクを実行するときは、start メソッドを前に呼び出し、stop メソッドを後で呼び出します。呼び出しの例を以下に示します。

// Show loading
viewControllerShowAjax();

// Tasks that take time including large calculations and ajax requests   
app.timeConsumingFunction();

// Hide loading
viewControllerHideAjax();

これはfirefoxでは機能しますが、IE または Chrome では機能しません。これに対する修正はありますか?

編集: 以下は私が使用している機能です:

function viewControllerInit() {
    // Other initializations
    ...

    // Initializing the activity indicator; the activity indicator is simply a jqueryui modal view with a spinjs spinner in it.
    $(this.ajaxModalSelector).dialog({
        resizable   : false,
    dialogClass : "no-close ajax",
    autoOpen    : false,
    height      : 500,
    width       : 500,
    modal       : true,
    open: function( event, ui ) {
        $(this.ajaxModalSelector).dialog("open");
            var opts = {
              lines: 12,
              length: 0,
              width: 20,
              radius: 40,
              color: '#000',
              speed: 1.3,
              trail: 50,
              shadow: false,
            };
            this.spinner = new Spinner(opts).spin(document.getElementById("ajax-modal"));
        },
        beforeClose: function( event, ui ) {
            this.spinner.stop();
        }
    });
}
// Opens the jquery ui modal view
function viewControllerShowAjax() {
    $(this.ajaxModalSelector).dialog("open");
}
// Closes the jquery ui modal view
function viewControllerHideAjax() {
    $(this.ajaxModalSelector).dialog("close");
}

編集:問題に関する詳細については; アクティビティ インジケーターに対して非表示関数が呼び出されない場合、時間のかかるタスクが完了した後に表示されることがわかりました。繰り返しますが、これは IE と Chrome の両方での動作ですが、Firefox ではそうではありません。

4

1 に答える 1

10

推定原因

これが機能しない理由は、JavaScript がシングル スレッドであるためです。

時間のかかる関数app.timeConsumingFunction()は、Chrome と IE での UI の更新をブロックします。

Firefox で動作する理由は単純に、FF には、いわば UI イベントを実行できるようにする別の実装があるためです (Canary と私は、Chrome にも UI の更新を個別に実行できる実験モードがあると信じています)。スレッド)。

一般に、ブラウザはペイント イベントなどのさまざまなイベントをキューに入れます。次に、このキューはイベントごとにトラバースされ、実行されます。

ただし、たとえば、キュ​​ー エントリが時間のかかる関数のコンテキストを実行している場合、キューには、そのキュー内の他のイベントを続行するための「呼吸スペース」がありません。

それは、他の方法ではスピナーをペイントするペイント イベントを実行することです。ブロックされているため、時間のかかる関数が終了するまでスピナーは表示されません。

setTimeout を使用した可能な解決策

setTimeoutこれを解決して機能させる方法は、またはWeb ワーカーを使用して実行を分割することです (以下の Web ワーカーの例を参照してください)。

たとえば、これを試して、現在のコードが改善されるかどうかを確認できます (これは疑わしいですが、単純なので試してみる価値があります)。実際にこれをテストするのに十分なコードが投稿にないため、理論と考えてください。この行を置き換えてみてください:

app.timeConsumingFunction();

setTimeout(app.timeConsumingFunction, 0); //or use 11 if no difference

それだけでは不十分な場合は、同様のセットアップを行う必要がありますが、可能であれば、操作のさまざまな段階を処理する部分に分割する関数の内部 (表示されていません) を使用します。スケルトンの例は次のとおりです。

app.timeConsumingFunction = function() {

    var hereIsAvailableToAllParts;

    function part1() {
        // step 1 in time-consuming operation
        setTimout(part2, 0);  //start next part
    }

    function part2() {
        // step 2 in time-consuming operation
        setTimout(part3, 0);
    }

    function part3() {
        // step 3 in time-consuming operation
        ...done or next...
    }
    setTimeout(part1, 0);
}

引数 0setTimeoutは、ブラウザーに、最初に利用可能な機会にこのイベントをキューに入れるように指示します。これは常に機能するとは限りませんが、代わりに、使用可能な最小キュー スライスに近い約 11 ミリ秒の間隔を使用できます。

このように操作を分割することで、ブラウザがたとえば描画イベントを間に実行できるようになり、スピナーを表示できるようになります。

Web Worker を使用した可能な解決策

コードを知らなければ、このシナリオで Web ワーカーを使用できるとは言えません。DOM アクセスなし、ストレージ アクセスなしなどの特定の制限があるためです。ただし、Web ワーカーのサポートは優れているため、可能であればこのアプローチをお勧めします。あなたのコード(制限を参照)。

ただし、純粋な計算を行う場合は、Web ワーカーをオプションとして検討してください:
https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers

必要最小限の例:

メイン スクリプトでは、次のように Web ワーカーを割り当てることができます。

var ww = new Worker(urlToWebWorkerScriptHere);

Web ワーカーはメッセージを介して通信するため、「私たちの」側でmessageイベントをリッスンします。

ww.onmessage = function (e) {

    var msg = e.data;

    /// message returned can be anything you like (see next section)
    if (msg === 'Done!') viewControllerHideAjax();
};

Web ワーカーは、別の JS ファイルとして読み込まれる別のスクリプトを使用するか、ちょっとしたトリックを使用して HTML コードでインライン化することができます (以下のフィドルを参照)。

スクリプトは分離されたコンテキストで実行され、すべての計算が行われます。完了すると、メイン スクリプトにシグナルが送信されます。

onmessage = function(e) {

    /// you can send any commands you want and call them what you want
    /// for example, I have called the command start

    if (e.data === 'start') {

        /// the time consuming stuff..

        /// when finished, send 'Done!' to main script
        postMessage('Done!');
    }
};

計算を開始するには、次のようにします。

// Show loading
viewControllerShowAjax();

// Tasks that take time including large calculations and ajax requests   
ww.postMessage('start');

(非表示は、'Done!' メッセージがワーカーから返されたときに呼び出されます)。

もちろん、多くのメッセージを送受信できます。たとえば、結果の一部を返したり、計算 (または演算) の次の部分をトリガーしたりできます。

次のフィドルで簡単なデモを作成しました。フィドルのループがビジーループ/「重い作業」を行っている場合でも、右ボタンをクリックできることに注意してください (例では、Web Worker をインライン化する方法も確認できます)。スクリプトを個別にロードする代わりに):

WEB WORKER DEMO

しかし、繰り返しになりますが、作業用のコードを見ないと、Web Worker を使用できるかどうかわかりません。

いずれにせよ、これはこれを解決する方法へのいくつかの指針を与えるはずです。

于 2013-07-18T15:47:04.290 に答える