如何在不冻结浏览器的情况下执行大量javascript代码
How to execute heavy javascript code without the browser freezing?
我有一个页面,它在加载后执行大量javascript代码。为了防止页面在加载时冻结,我将执行间隔成批,中间有一些"无执行"时间(使用超时),一切都很顺利。
最近,我不得不添加额外的重型javascript代码,这些代码可以在客户端操作时执行,但这些操作甚至可以在原始重型脚本执行之前发生。这一次,间隔操作没有帮助,因为在一个脚本的"停机时间",另一个脚本可以运行,反之亦然,这将导致浏览器冻结。
事实上,问题更为复杂,因为有多个这样的操作,每个操作都执行不同的重脚本,而且与其他脚本相比,每个脚本都有不同的"优先级"来决定我希望它以多快的速度完成。
我的问题是,在这种情况下常见的做法是什么?我试着想办法解决它,但我所能想到的是一个相当复杂的解决方案,这几乎就像用javascript编写操作系统一样——也就是说,编写一个每X次执行一次的"管理器"代码(使用"中断"),并选择切换到哪个"上下文"(=现在应该运行哪个作业),等等
然而,这对我来说听起来相当复杂,我希望可能还有其他解决方案。我的问题听起来像是很多人以前偶然发现的问题,所以即使唯一的解决方案是我建议的,我也会认为有人已经写过了,或者有一些图书馆支持。
如有任何帮助,我们将不胜感激。非常感谢。
==编辑==
所谓"重代码",我指的是例如对大量元素的DOM操作。
您需要考虑将UI/Problem域定义为一组异步任务。以下是更多见解http://alexmaccaw.com/posts/async_ui直到我为你想出一个更好的答案。
如果你不想阻止你的脚本,你可以使用web工作者。请参阅MDN:使用网络工作者以获得一个很好的介绍。请注意,网络工作者仍然相对较新,大多数浏览器都不支持。
然而,如果你想支持所有浏览器和为你的"重脚本"添加某种优先级,你应该自己定义一些东西,例如:
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)
将任务添加到特定的工作者队列中。
- 无法在通过jQuery的ajax加载的页面中执行javascript
- 在Safari执行javascript之前对其进行修改
- 如何在执行此特定onclick事件时执行JavaScript函数
- 如何在从浏览缓存加载页面时执行javascript
- 使用Rhino和ASE执行Javascript的区别
- 如何在加载完整页面后严格执行javascript代码
- 在动态加载的对话框中执行Javascript
- 在Sinatra中执行Javascript
- 通过AJAX加载页面并执行javascript和CSS
- 适用于多种浏览器的Selenium-需要能够执行javascript的webDriver
- 如何在seleniumwebdriver中执行javascript提示并等待接受输入
- 在window.open()生成的窗口中执行JavaScript
- AJAX成功回调-执行javascript时出现问题
- 通过指令在控制器中执行javascript函数
- 从React Native Android原生地执行JavaScript代码
- iframe未执行Javascript方法(PHP)
- 执行JavaScript代码,使用selenium webdriver或WatiN从控制台获取日志
- 通过web驱动程序异步执行Javascript
- 如何在长时间执行JavaScript期间显示微调器
- 点击困难时执行javascript函数