为什么缓存未清空时pixels.data比对循环开头为false、赋值后为true
问题本质
你遇到的是JavaScript引用类型的相等判断逻辑问题,和你的缓存数组是否清空没有关系。
具体原因
getImageData返回的pixels.data是Uint8ClampedArray类型,属于引用类型。JavaScript中对引用类型使用==/===判断时,比较的是两个变量是否指向内存中的同一个对象实例,而非对比对象内部的内容是否一致。- 每次循环执行
ctx.getImageData()时,浏览器都会生成一个全新的ImageData实例,对应的data属性也是全新的数组实例。哪怕两个分块的像素值完全相同,只要是两次getImageData返回的结果,它们的内存地址就不一样,直接用==判断自然永远返回false。 - 赋值后判断返回
true的原因是你直接把本次新生成的pixels.data的引用赋值给了cachedImage[y][x],两个变量此时指向内存中的同一个数组,相当于是自己和自己比较,所以判断结果为真,这个逻辑并没有实现你想要的「新旧像素内容比对」的需求。
解决方法
你需要手动比对两个像素数组的内容,而不是直接对比引用,可以封装专用的比对函数:
// 像素内容比对工具函数 function isPixelDataEqual(pixelArr1, pixelArr2) { // 引用相同直接返回真 if (pixelArr1 === pixelArr2) return true // 空值或者长度不一致直接返回假 if (!pixelArr1 || !pixelArr2 || pixelArr1.length !== pixelArr2.length) return false // 逐位比对像素值 for (let i = 0; i < pixelArr1.length; i++) { if (pixelArr1[i] !== pixelArr2[i]) return false } return true }
将你原有代码中的判断逻辑替换为调用该函数即可:
// 替换原有 if(pixels.data == cachedImage[y][x]) 逻辑 if(isPixelDataEqual(pixels.data, cachedImage[y][x])) { // 像素未变化,跳过绘制 } else { cachedImage[y][x] = pixels.data; ctxFinal.putImageData(pixels,x*widthChunk,y*heightChunk) }
如果你的分块尺寸较大,逐位比对性能开销较高,也可以预先计算像素数组的哈希值存入缓存,直接比对哈希值即可,不用每次都遍历全部分块像素。
内容的提问来源于stack exchange,提问作者ioi-xd
相关产品推荐
相关产品推荐

