如何在不冻结浏览器的情况下执行繁重的javascript代码?
我有一个页面,加载后执行繁重的javascript代码。为了防止页面在加载时冻结,我将执行分为若干批,中间有一些“不执行”的时间(使用超时),并且运行良好 最近,我不得不添加额外的繁重javascript代码,这些代码可以在客户端操作时执行,但这些操作甚至可以在原始繁重脚本执行完毕之前发生。这一次,间隔操作将没有帮助,因为在一个脚本“停机”时,另一个脚本可以运行,反之亦然,这将导致浏览器冻结 问题实际上更复杂,因为有多个这样的动作,每个动作执行一个不同的重脚本,每个脚本都有一个不同的“优先级”,与其他脚本相比,我希望它以多快的速度完成 我的问题是,在这种情况下,通常的做法是什么?我试着想办法解决这个问题,但我能想到的只是一个相当复杂的解决方案,就像用javascript编写一个操作系统——也就是说,编写一个“管理器”代码,每X次执行一次(使用“中断”),然后选择要切换到哪个“上下文”(=现在应该运行哪个作业),等等 然而,对我来说,这听起来相当复杂,我希望有其他的解决方案。我的问题听起来像是很多人以前碰到过的问题,所以即使唯一的解决方案是我的建议,我也会假设已经有人写了它,或者有一些图书馆支持这一点 任何帮助都将不胜感激。多谢各位如何在不冻结浏览器的情况下执行繁重的javascript代码?,javascript,html,scheduling,freeze,Javascript,Html,Scheduling,Freeze,我有一个页面,加载后执行繁重的javascript代码。为了防止页面在加载时冻结,我将执行分为若干批,中间有一些“不执行”的时间(使用超时),并且运行良好 最近,我不得不添加额外的繁重javascript代码,这些代码可以在客户端操作时执行,但这些操作甚至可以在原始繁重脚本执行完毕之前发生。这一次,间隔操作将没有帮助,因为在一个脚本“停机”时,另一个脚本可以运行,反之亦然,这将导致浏览器冻结 问题实际上更复杂,因为有多个这样的动作,每个动作执行一个不同的重脚本,每个脚本都有一个不同的“优先级”,
==编辑==
所谓“繁重的代码”,我指的是大量元素的DOM操作。您需要考虑将UI/问题域定义为一组异步任务。在我为您制定一个更好的答案之前,这里有更多的见解。如果您不想阻止脚本,可以使用。请参阅以获得良好的介绍。请注意,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();
函数WorkerQueue(此参数){
this.queue=[];
this.this_参数=this_参数;
这个优先级=1;
}
WorkerQueue.prototype.enqueue=函数(回调){
this.queue.push(回调);
}
WorkerQueue.prototype.dequeue=函数(){
返回此.queue.splice(0,1)[0];
}
函数WorkerPool(){
this.pool=[];
this.status=“正在运行”;
this.timeout=null;
}
WorkerPool.prototype.addWorker=函数(此参数){
this.pool.push(newworkerqueue(this_参数));
返回this.pool[this.pool.length-1];
}
WorkerPool.prototype.nextTask=函数(){
var max_priority=0;
var max_priority_task=this.pool.length;
对于(变量i=0;imax_priority&&this.pool[i].queue.length!==0){
max_priority=this.pool[i]。优先级;
最大优先级任务=i;
}
}
//池为空或所有任务的优先级无效
if(最大优先级任务===this.pool.length)
回来
if(this.pool[max\u priority\u task]。this\u参数)
this.pool[max\u priority\u task].dequeue().apply(this.pool[max\u priority\u task].this\u参数);
其他的
此.pool[max_priority_task].dequeue().apply();
如果(this.status!=“正在运行”)
回来
this.timeout=setTimeout(函数(t){return function(){t.nextTask();};}(this),1000);
}
var Workers=new WorkerPool();
var worker1=Workers.addWorker();
worker1.enqueue(函数(){
console.log(“你好”);
});
worker1.enqueue(函数(){
console.log(“世界”);
});
var worker2=Workers.addWorker();
worker2.priority=2;
worker2.this_参数=worker2;
worker2.enqueue(函数(){
日志(“Worker 2-更改优先级”);
这个优先级=0.2;
});
worker2.enqueue(函数(){
控制台日志(“工作人员2-变更后”);
});
Workers.nextTask();
在本例中,每个“繁重脚本”都是一个工作者,基本上是一个任务队列。您可以使用
addWorker
在池中创建一个新的worker,并使用worker.enqueue(callback)
将任务添加到特定的worker队列中什么类型的“重”javascript?似乎您想在javascript中实现某种分时线程机制,据我所知,Javascript做不到的事情。如果在前端做一些事情需要很长时间(“前端”=您的例子中的Javascript),我通常会坐下来仔细地重新考虑我的应用程序的设计。在这里,您可以使用jquery。使用jqueryajax调用执行大量调用。bPratik:很抱歉,我从来没有像我应该关注的那样关注过网站的这一方面,我会确保它不会再次发生。关于其余的评论:我知道JS中没有线程机制,这就是为什么我要说在单核PC上使用操作系统。在这种情况下,Ajax调用对我没有帮助,因为大部分工作是DOM操作。由于OP编辑了一个问题,澄清了“重代码”是指DOM操作,很有意思的是,WebWorker将如何解决这个问题?将innerHTML发送给WebWorker以进行非DOM文本操作?@Azder:要么这样(WebWorker无法操作DOM内容),要么使用某种调度/自定义工作池。顺便说一句,我在写了我的答案后读了你的链接文章。虽然基本上是相同的方法,但在繁重的任务上使用setInterval
几乎总是一个坏主意。TBH我只是提供了我得到的第一个google结果,并不是我读到的:)我总是使用setTimeout。至于DOM,就因为我知道它不能操作DOM内容,我写了“将innerHTML发送给WebWorker进行非DOM文本操作”;)