Javascript 递归对Firefox来说是昂贵的
编辑:仅在Firefox中出现!(我使用的是22.0)查看底部的浏览器比较 我试图通过复制像素数据并逐步将alpha值从255更改为0(背景为黑色),在画布上创建“淡入黑色”效果 奇怪的是,如果我只是延迟第二次迭代的Javascript 递归对Firefox来说是昂贵的,javascript,performance,firefox,canvas,pixel-manipulation,Javascript,Performance,Firefox,Canvas,Pixel Manipulation,编辑:仅在Firefox中出现!(我使用的是22.0)查看底部的浏览器比较 我试图通过复制像素数据并逐步将alpha值从255更改为0(背景为黑色),在画布上创建“淡入黑色”效果 奇怪的是,如果我只是延迟第二次迭代的fadeToBlack(像素操作的第一次迭代) 这到底是怎么回事 编辑:我在几个浏览器中进行了测试,下面是所有15次迭代的结果(以毫秒为单位) Browser |递归|异步 =========+===========+============ Firefox | 1652†| 113
fadeToBlack
(像素操作的第一次迭代)
这到底是怎么回事
编辑:我在几个浏览器中进行了测试,下面是所有15次迭代的结果(以毫秒为单位)
Browser |递归|异步
=========+===========+============
Firefox | 1652†| 1136
铬| 976 | 978
歌剧院| 12929 | 13855
IE | 855 | 854
†第一次迭代非常昂贵(500ms)。我认为这会将函数之间的跳跃减少一半,因为您只调用一次,直到函数死亡(使用setTimeout的异步调用时),但是如果您通过从内部调用使用递归,它将在该点停止并跳转到下一个调用,依此类推,直到完成最后一个调用,然后逐渐进行递归,从它停止的行调用上一个函数,继续使用递归返回的值并返回到上一个,我可以看到性能和方法上的差异。我想问一下,它是否会给你同样的结果,我怀疑不会是这样 TL;DR setTimeout:异步调用(独立),递归:同步(依赖)。 图形演示:
我认为这样可以将函数之间的跳跃减少一半,因为在函数死亡之前只调用一次(使用setTimeout进行异步调用时),但是如果通过从内部调用来使用递归,它将在该点停止并跳转到下一个调用,依此类推,直到完成最后一个调用,然后逐渐进行递归,从它停止的行调用上一个函数,继续使用递归返回的值并返回到上一个,我可以看到性能和方法上的差异。我想问一下,它是否会给你同样的结果,我怀疑不会是这样 TL;DR setTimeout:异步调用(独立),递归:同步(依赖)。 图形演示:
这很奇怪,但如果使用setTimeout,则会使函数以异步方式执行,当前函数将继续工作,同时将下一个调用放入队列中,以便在后台运行。这不再是递归,因为您不依赖于它返回的值。我感兴趣的是知道这种提升的原因,是不是当你调用异步调用并结束当前调用,从内存中删除当前的流,并认为它与队列无关?当我问这个问题时,我对异步/递归有点模糊,但现在我已经读了一点了。。。我仍然不知道性能提升来自何方。我想这可能是由于两个函数同时访问相同的5mB数据集(this.imageData)而导致的非常特定于引擎的原因。我可能会在不同的浏览器中做一些测试,看看会发生什么。@CME64完成!看起来绝对像一个引擎怪癖!这很奇怪,但如果使用setTimeout,则会使函数以异步方式执行,当前函数将继续工作,同时将下一个调用放入队列中,以便在后台运行。这不再是递归,因为您不依赖于它返回的值。我感兴趣的是知道这种提升的原因,是不是当你调用异步调用并结束当前调用,从内存中删除当前的流,并认为它与队列无关?当我问这个问题时,我对异步/递归有点模糊,但现在我已经读了一点了。。。我仍然不知道性能提升来自何方。我想这可能是由于两个函数同时访问相同的5mB数据集(this.imageData)而导致的非常特定于引擎的原因。我可能会在不同的浏览器中做一些测试,看看会发生什么。@CME64完成!看起来绝对像一个引擎怪癖!
function fadeToBlack () {
if(typeof this.recursion === 'undefined' || this.recursion === 0) {
this.recursion = 1;
this.imageData = this.ctx.getImageData(0, 0, this.width, this.height);
this.imageDataArray = this.imageData.data;
this.pixelCount = this.imageDataArray.length/4;
this.fadeToBlack();
}
else if (this.recursion <= 15){
console.time('Change alpha ' + this.recursion);
for (var i = 0; i < this.pixelCount; i++){
this.imageDataArray[i * 4 + 3] = 255 - 255 / 15 * this.recursion;
}
console.timeEnd('Change alpha ' + this.recursion);
this.ctx.putImageData(this.imageData, 0, 0);
this.recursion++;
setTimeout(function(){
this.fadeToBlack();
}.bind(this), 50);
}
else {
this.recursion = 0;
}
};
function fadeToBlack () {
if(typeof this.recursion === 'undefined' || this.recursion === 0) {
this.recursion = 1;
this.imageData = this.ctx.getImageData(0, 0, this.width, this.height);
this.imageDataArray = this.imageData.data;
this.pixelCount = this.imageDataArray.length/4;
//This is the only difference!
setTimeout(function(){
this.fadeToBlack();
}.bind(this), 0);
}
else if (this.recursion <= 15){
console.time('Change alpha ' + this.recursion);
for (var i = 0; i < this.pixelCount; i++){
this.imageDataArray[i * 4 + 3] = 255 - 255 / 15 * this.recursion;
}
console.timeEnd('Change alpha ' + this.recursion);
this.ctx.putImageData(this.imageData, 0, 0);
this.recursion++;
setTimeout(function(){
this.fadeToBlack();
}.bind(this), 50);
}
else {
this.recursion = 0;
}
};