2

読み込み後に重い JavaScript コードを実行するページがありました。読み込み時にページがフリーズするのを防ぐために、(タイムアウトを使用して) 間に「非実行」時間を置いて実行をバッチに分けたところ、うまくいきました。

最近、クライアント アクションで実行できる追加の重い JavaScript コードを追加する必要がありましたが、これらのアクションは、元の重いスクリプトの実行が完了する前でも発生する可能性があります。今回は、アクションの間隔を空けても役に立ちません。1 つのスクリプトの「ダウンタイム」で別のスクリプトが実行され、その逆もまた同様であり、ブラウザがフリーズするからです。

このようなアクションが複数あり、それぞれが異なる重いスクリプトを実行し、各スクリプトには、他のものと比較してどれだけ速く終了させたいかという「優先度」があるため、実際には問題はより複雑です。

私の質問は、そのような状況での一般的な慣行は何ですか? 私はそれを解決する方法を考えてみましたが、私が考えることができたのは、JavaScriptでオペレーティングシステムを書くのとほとんど同じような非常に複雑な解決策、つまり、X回ごとに実行される「マネージャー」コードを書くことでした( 「割り込み」)、どの「コンテキストに切り替えるか」( = 現在実行するジョブ) などを選択します。

しかし、これは私にはかなり複雑に聞こえます。他の解決策があるかもしれないと思っていました. 私の問題は、多くの人が以前に遭遇したと思われる問題のように思えます。そのため、唯一の解決策が私が提案したものであっても、誰かが既に書いているか、ライブラリのサポートがあると思います。

どんな助けでも大歓迎です。ありがとうございました。


== 編集 ==
「重いコード」とは、たとえば、多数の要素の DOM 操作を意味します。

4

2 に答える 2

0

UI/問題ドメインを一連の非同期タスクとして定義することを考える必要があります。より良い答えを作成するまで、ここにいくつかの洞察がありますhttp://alexmaccaw.com/posts/async_ui 。

于 2012-07-25T18:56:29.890 に答える
0

スクリプトをブロックしたくない場合は、web workerを使用できます。MDN: Using web workerを参照してください。Web ワーカーはまだ比較的新しく、ほとんどのブラウザーでサポートされていないことに注意してください。

ただし、すべてのブラウザをサポートし、「重いスクリプト」に何らかの優先順位を追加したい場合は、次のように自分で何かを定義する必要があります。

function WorkerQueue(this_argument){
    this.queue = [];
    this.this_argument = this_argument;
    this.priority = 1;
}

WorkerQueue.prototype.enqueue = function(callback){
    this.queue.push(callback);
}

WorkerQueue.prototype.dequeue = function(){
    return this.queue.splice(0,1)[0];   
}

function WorkerPool(){
    this.pool = [];
    this.status = "running";
    this.timeout = null;
}

WorkerPool.prototype.addWorker = function(this_argument){
    this.pool.push(new WorkerQueue(this_argument));
    return this.pool[this.pool.length - 1];
}

WorkerPool.prototype.nextTask = function(){
    var max_priority = 0;
    var max_priority_task = this.pool.length;
    for(var i = 0; i < this.pool.length; ++i){
        if(this.pool[i].priority > max_priority && this.pool[i].queue.length !== 0){
            max_priority = this.pool[i].priority;
            max_priority_task = i;
        }
    }
     // pool is empty or all tasks have an invalid priority  
    if(max_priority_task === this.pool.length)
        return;

    if(this.pool[max_priority_task].this_argument)
        this.pool[max_priority_task].dequeue().apply(this.pool[max_priority_task].this_argument);
    else
        this.pool[max_priority_task].dequeue().apply();

    if(this.status !== "running")
        return;
    this.timeout = setTimeout(function(t){return function(){t.nextTask();};}(this),1000);
}

var Workers = new WorkerPool();
var worker1 = Workers.addWorker();
worker1.enqueue(function(){
    console.log("Hello");
});
worker1.enqueue(function(){
    console.log("World");
});

var worker2 = Workers.addWorker();
worker2.priority = 2;
worker2.this_argument = worker2;
worker2.enqueue(function(){
    console.log("Worker 2 - changing priority");
    this.priority = .2;
});
worker2.enqueue(function(){
    console.log("Worker 2 - after change"); 
});

Workers.nextTask();

デモ

この場合、すべての「重いスクリプト」はワーカーであり、基本的にはタスクのキューです。を使用してプールに新しいワーカーを作成し、 を使用addWorkerして特定のワーカー キューにタスクを追加しworker.enqueue(callback)ます。

于 2012-07-25T20:08:27.993 に答える