2

我有一个页面在加载后执行繁重的 javascript 代码。为了防止页面在加载时冻结,我将执行分成批次,中间有一些“不执行”时间(使用超时),并且事情运行良好。

最近,我不得不添加额外的重型 javascript 代码,这些代码可以在客户端操作时执行,但这些操作甚至可以在原始重型脚本执行完成之前发生。这一次,间隔操作将无济于事,因为在一个脚本的“停机时间”,另一个可以运行,反之亦然,这将导致浏览器冻结。

问题实际上更复杂,因为有多个此类操作,每个操作执行不同的繁重脚本,并且与其他脚本相比,每个脚本类型对于我希望它完成的速度有不同的“优先级”。

我的问题是,在这种情况下的常见做法是什么?我试着想办法解决它,但我能想到的只是一个相当复杂的解决方案,它几乎就像用 javascript 编写操作系统一样——即编写一个每 X 次执行的“管理器”代码(使用“中断”),并选择哪个“要切换到的上下文”(=现在应该运行哪个作业)等等......

然而,这对我来说听起来很复杂,我希望那里可能有其他解决方案。我的问题听起来像是我认为很多人以前偶然发现的问题,所以即使唯一的解决方案是我建议的,我也会假设有人已经写了它,或者有一些库支持。

任何帮助将不胜感激。谢谢你。


== 编辑 ==
通过“繁重的代码”,我的意思是例如对大量元素的 DOM 操作。

4

2 回答 2

0

您需要考虑将您的 UI/问题域定义为一组异步任务。在我为您制定更好的答案之前,这里有一些更深入的见解http://alexmaccaw.com/posts/async_ui 。

于 2012-07-25T18:56:29.890 回答
0

如果您不想阻止您的脚本,您可以使用web workers。请参阅MDN:使用 web worker以获得很好的介绍。请注意,网络工作者仍然相对较新,大多数浏览器都不支持。

但是,如果您想支持所有浏览器为您的“繁重脚本”添加某种优先级,您应该自己定义一些东西,例如:

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 回答