如何在javascript中分解长时间运行的函数,同时保持性能
我有一个长期运行的功能。它遍历一个大数组并在每个循环中执行一个函数如何在javascript中分解长时间运行的函数,同时保持性能,javascript,Javascript,我有一个长期运行的功能。它遍历一个大数组并在每个循环中执行一个函数 longFunction : function(){ var self = this; var data = self.data; for(var i=0; len = data.length; i<len; i++){ self.smallFunction(i); } }, smallFunction : function(index)
longFunction : function(){
var self = this;
var data = self.data;
for(var i=0; len = data.length; i<len; i++){
self.smallFunction(i);
}
},
smallFunction : function(index){
// Do Stuff!
}
因此,我在这里删除循环,并引入一个自调用函数,它会在每次迭代中增加索引。为了将控制权返回到主UI线程以防止javascript执行警告方法,我添加了一个setTimeout
,以允许它在每次迭代后有时间进行更新。问题是,用这种方法完成实际工作实际上需要10倍的时间。虽然setTimeout
设置为0,但实际情况似乎是等待10毫秒。它在大型阵列上构建得非常快。删除setTimeout
并让longFunction
调用本身可以提供与原始循环方法相当的性能
我需要另一个解决方案,它的性能与循环相当,但不会导致javascript执行警告。不幸的是,此实例中无法使用webWorkers
需要注意的是,在此过程中,我不需要完全响应的UI。刚好可以每隔几秒钟更新一次进度条
将它分解成块循环是一种选择吗?即一次执行500次迭代、停止、超时、更新进度条、执行下一个500次等。。等等
还有更好的吗
回答:
唯一的解决办法似乎是将工作分块
通过向我的自调用函数添加以下内容,我允许UI每250次更新一次:
longFunction : function(index){
var self = this;
var data = self.data;
self.smallFunction(index);
var nextindex = i+1;
if(data.slides[nextindex){
if(nextindex % 250 === 0){
setTimeout(function(){
self.longFunction(nextindex);
},0);
}
else {
self.longFunction(nextindex);
}
}
else {
//WORK FINISHED
}
},
smallFunction : function(index){
// Do Stuff!
}
我在这里所做的就是检查下一个索引是否可以被250整除,如果可以,那么我们使用一个超时来允许主UI线程更新。如果不是,我们直接再打一次。问题解决了 下面是一些批处理代码,这些代码是根据我之前的回答修改的:
var n = 0,
max = data.length;
batch = 100;
(function nextBatch() {
for (var i = 0; i < batch && n < max; ++i, ++n) {
myFunc(n);
}
if (n < max) {
setTimeout(nextBatch, 0);
}
})();
var n=0,
max=数据长度;
批次=100;
(函数nextBatch(){
对于(变量i=0;i
实际上1500次超时算不了什么,所以您可以简单地执行以下操作:
var i1 = 0
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(i1++) }, 0)
在Node.js下,您还可以使用setImmediate(…)
还有更好的吗
如果你同意它只在现代浏览器中工作,那么你应该研究一下“网络工作者”,它可以让你在后台执行JS
是否可以在后台异步运行它?如果你不能做到这一点,是的,把它分成几块。你的函数对每一项具体做了什么?也许您可以通过一次执行多个setTimeout来并行它们。@Patashu-web workers在所有浏览器中都不可用。。。所以分成合理的块看起来是安全的方法。
setTimeout
的最小值为4ms。是的,将循环分解为500个循环是一个不错的方法。@gordyr-iFrame确实占用了相当大的开销,似乎要花12秒才能生成1000个循环。您的方法和我刚才添加到问题中的方法都非常有效。我希望你的速度稍微快一点,因为这样可以避免函数开销。谢谢alnitak。虽然这是正确的,但它会大大降低速度,因为我们对每个迭代都使用超时。在大多数浏览器中,0超时实际上等于10毫秒左右,这意味着对于一组2000长的进程,我们将在不需要的加载时间上增加20秒。我们提出的解决方案只在指定的时间间隔内运行超时,允许其他解决方案立即启动。我确信您不理解此解决方案。设置超时将同时启动。在第一个开始执行之前,将经过几毫秒。但其他人将毫不拖延地跟进。当我说1500次超时不算什么时,我并不是说1500*10ms不算多。我的意思是V8可以轻松地容纳数千个等待的超时,他们的时间已经到了!所以他们会一个接一个的执行。哦,我明白了!!对不起,我完全误入歧途了。嗯,这实际上可能是最好的解决方案。我会做一些测试,然后再给你回复。如果它比我现在使用的更好,我会告诉你答案。谢谢是的,在测试了你的建议之后,它是完美的,除了不能保证顺序这一事实。我将它们封装在一个匿名函数中,并传入索引,但在大型数组中,我发现了顺序上的变化。可能是其中一个超时在另一个超时之前执行。我不知道为什么会这样。我本以为所有浏览器都会对它们进行排队,但事实似乎并非如此。如果我在某个地方犯了错误,我会做一些进一步的测试。我对webworkers有很多经验,但不幸的是,由于DOM访问限制,它们不适用于这种情况,因此无法使用。
var i1 = 0
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(i1++) }, 0)
function doSomething(obj) {
obj.count++
...put actual code here
}
var obj = {count: 0}
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(obj) }, 0)