web-dev-qa-db-ja.com

JavaScriptでバックグラウンドタスクを実行する

クライアントで実行する必要があるCPU集中タスクがあります。理想的には、jqueryを使用して関数を呼び出し、進行イベントをトリガーできるようにして、UIを更新できるようにします。

Javascriptはスレッド化をサポートしていないことは知っていますが、setTimeoutを使用してスレッド化を模倣しようとするいくつかの有望な記事を見てきました。

これに使用する最善のアプローチは何ですか?ありがとう。

42
Rob

表示するいくつかのデータをクランチする間、UIスレッドを解放する必要がある最近解決した同様の問題がありました。

いくつかのシナリオを処理するために、Background.jsライブラリを作成しました。シーケンシャルバックグラウンドキュー(WorkerQueueライブラリに基づく)、各タイマーでそれぞれが呼び出されるジョブのリスト、および作業を小さなチャンクに分割するための配列反復子。ここの例とコード: https://github.com/kmalakoff/background

楽しい!

20
Kevin

基本的に、あなたがしたいことは、操作を断片に分割することです。したがって、処理するアイテムが10,000個あるとし、それらをリストに保存してから、各呼び出しの間にわずかな遅延をかけて少数のアイテムを処理します。使用できる簡単な構造を次に示します。

function performTask(items, numToProcess, processItem) {
    var pos = 0;
    // This is run once for every numToProcess items.
    function iteration() {
        // Calculate last position.
        var j = Math.min(pos + numToProcess, items.length);
        // Start at current position and loop to last position.
        for (var i = pos; i < j; i++) {
            processItem(items, i);
        }
        // Increment current position.
        pos += numToProcess;
        // Only continue if there are more items to process.
        if (pos < items.length)
            setTimeout(iteration, 10); // Wait 10 ms to let the UI update.
    }
    iteration();
}

performTask(
    // A set of items.
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'],
    // Process two items every iteration.
    2,
    // Function that will do stuff to the items. Called once for every item. Gets
    // the array with items and the index of the current item (to prevent copying
    // values around which is unnecessary.)
    function (items, index) {
        // Do stuff with items[index]
        // This could also be inline in iteration for better performance.
    });

また、 Google Gearsは別のスレッドでの作業をサポートしています にも注意してください。 Firefox 3.5では、 同じことをする独自のワーカー も導入しました(ただし、 W3標準 に従いますが、Google Gearsは独自のメソッドを使用します)。

38
Blixt

ブラウザの使用を強制できる場合、またはブラウザがFirefoxの新しいバージョンであることを既に知っている場合は、Mozillaの新しい WebWorkers を使用できます。新しいスレッドを生成できます。

8
Sinan Taifour

要件に応じて、Gearsを使用すると簡単に降りることができます。 Gearsはスレッドをサポートしており、必要な処理を実行できます。

前述のように、setTimeoutはもう1つのオプションです。タスクのタイプに応じて、ループの各反復を間隔を空けて個別のsetTimeout呼び出しに渡すことができます。または、メインアルゴリズムの一部を、各反復を呼び出すのと同じ方法。

4

すばらしい答えケビン!数年前に似たようなものを書きましたが、それほど洗練されていません。誰かがそれを望むならば、ソースコードはここにあります:

http://www.leapbeyond.com/ric/jsUtils/TaskQueue.js

run()メソッドを持つものはすべてタスクとしてキューに入れることができます。タスクは、自分自身を再キューイングして、作業をチャンクで実行できます。タスクに優先順位を付けたり、自由に追加/削除したり、キュー全体を一時停止/再開したりすることができます。非同期操作でうまく機能します。

基本的な使い方はとても簡単です:

var taskQueue = new TaskQueue();
taskQueue.schedule("alert('hello there')");

.jsファイルのヘッダーコメントは、より高度な例を提供します。

2
rkagerer

誰かが簡単なコピー&ペースト可能なコードを望んでいる場合の問題に対する私の解決策は次のとおりです。

    var iterate = function (from, to, action, complete) {
        var i = from;
        var impl = function () {
            action(i);
            i++;
            if (i < to) setTimeout(impl, 1);
            else complete();
        };
        impl();
    };
2
ironic

これは、JavaScriptでスレッドを作成する方法の非常に基本的な例です。スレッド機能を中断するのはユーザー次第です(yeld命令)。必要に応じて、mywhileループの代わりにsetTimeoutを使用して、スケジューラを定期的に実行できます。また、この例はJavaScriptバージョン1.7以降(firefox 3以降)でのみ機能することにも注意してください。ここで試すことができます。 http://jslibs.googlecode.com/svn/trunk/jseval.html

//// thread definition
function Thread( name ) {

    for ( var i = 0; i < 5; i++ ) {

        Print(i+' ('+name+')');
        yield;
    }
}

//// thread management
var threads = [];

// thread creation
threads.Push( new Thread('foo') );
threads.Push( new Thread('bar') );

// scheduler
while (threads.length) {

    var thread = threads.shift();
    try {
        thread.next();
        threads.Push(thread);
    } catch(ex if ex instanceof StopIteration) { }
}

出力は次のとおりです。

0 (foo) 0 (bar) 1 (foo) 1 (bar) 2 (foo) 2 (bar) 3 (foo) 3 (bar) 4 (foo) 4 (bar) 
1

私が最も強く推奨するのは、操作中に単純なloading.gifを表示することです。ユーザーは、しばらく時間がかかる可能性があると「言われた」場合、ある程度の期間を受け入れることがよくあります。

Ajaxload-Ajax loading gifジェネレーター

1
dbd