请大神解答Zepto assets模块的原理?
Zepto 的 assets模块 ,该模块“实验性支持从DOM中移除image元素后清理iOS的内存”,我不明白为什么要这样做,直接将DOM remove掉不就行了吗?希望大神能解答,谢谢!
;(function($){
var cache = [], timeout
$.fn.remove = function(){
return this.each(function(){
if(this.parentNode){
if(this.tagName === 'IMG'){
cache.push(this)
this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
if (timeout) clearTimeout(timeout)
timeout = setTimeout(function(){ cache = [] }, 60000)
}
this.parentNode.removeChild(this)
}
})
}
})(Zepto)
Answers
这个要从mobile safari严格的资源占用限制说起;mobile safari要比桌面版的浏览器的资源占用限制严格的多:
https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html#//apple_ref/doc/uid/TP40006482-SW15
其中一条相关的限制就是:**When Mobile Safari has loaded between 8 to 10 MB of image data it will simply stop displaying any more images. It might even crash.**
当Mobile Safari加载8-10M左右图像数据的时候,将会停止显示甚至Crash,比如下面的这种应用场景。
为了解决这个问题,我们就要回收掉这些图片资源。
想到的方法一:
var img = document.getElementById('previous');
img.parentNode.removeChild(img);
但是令人遗憾的是,出于某些原因,真正的图片数据根本没法释放,那应该怎么办呢?如果我们用一张非常小的图片替换掉原来的大图片,原来的图片数据是不是就会被清空掉?Let's Try。
能起作用的方法:
var img = document.getElementById('previous');
img.src = 'images/empty.gif';
这个方法貌似起作用了!我们用一张非常小的gif图片变更掉原先图片的src,原来的大图片得到释放了,黑科技万岁啊!但是.......故事显然还没有结束,目前为止,你还需要关注以下三件非常重要的事情:
-
src替换法不会使得图片资源马上释放,垃圾回收机制将在相当长的一段时间后才能回收掉这些内存资源,因此,当你在使用场景里太快的添加img资源的时候,还是会发生讨厌的事情!
-
Mobile Safari似乎不能再加载额外的图像资源,即使我们用了上面的黑科技回收掉了一部分或者全部的资源,除非重新加载整个页面来进行测试验证,这tm真是快把人逼疯了。
-
如果你想要在DOM中移除image元素,在变更src之前你还必须确保这个element没有被垃圾回收处理掉,不然老图片数据也有可能在这种情况下不得释放。
因此,终极的解决方案应该是:
var img = document.getElementById('previous');
img.parentNode.removeChild(img);
img.src = 'data:image/gif;base64,' +
'R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
window.timeout(function() {
img = null;
}, 60000);
这个故事的由来和贡献者来自于这个博客内容:
http://www.fngtps.com/2010/mobile-safari-image-resource-limit-workaround/
,正是这个作者向zepto贡献了这个黑科技。
作者还测试了一下assets插件~