我有一个页面,在加载后执行繁重的javascript代码。为了防止页面在加载时冻结,我将执行间隔为两个“无执行”时间(使用超时),并且运行良好。
最近,我不得不添加额外的重量级javascript代码,这些代码可以在客户端操作时执行,但这些操作甚至可以在原始繁重的脚本执行完毕之前发生。这一次,间隔操作将无济于事,因为在一个脚本的“停机时间”,另一个脚本可以运行,反之亦然,这将导致浏览器冻结。
问题实际上更复杂,因为有多个这样的动作,每个动作执行不同的重脚本,并且每个脚本对于我希望它完成的速度与其他脚本相比具有不同的“优先级”的。
我的问题是,这种情况下的常见做法是什么?我试着想办法解决它,但我能想到的只是一个非常复杂的解决方案,就像在javascript中编写一个操作系统一样 - 即编写一个每X次执行一次的“管理器”代码(使用一个“中断”),并选择“切换到的上下文”(=现在应该运行哪个作业),等等......
然而,这对我来说听起来很复杂,我希望可能还有其他解决方案。我的问题听起来像是我以前认为很多人偶然发现的问题,所以即使唯一的解决方案是我建议的,我也会假设某人已经写过它,或者有一些图书馆支持这个。
非常感谢任何帮助。谢谢。
==编辑==
通过“重代码”,我的意思是例如对大量元素的DOM操作。
答案 0 :(得分:0)
您需要考虑将UI /问题域定义为一组异步任务。在我为您制定更好的答案之前,我需要进一步了解http://alexmaccaw.com/posts/async_ui。
答案 1 :(得分:0)
如果您不想阻止脚本,可以使用web workers。有关详细介绍,请参阅MDN: Using web workers。请注意,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)
将任务添加到特定工作线队列。