最近有一些关于 Fabrice Bellard 的 BPG 图像格式 (http://bellard.org/bpg/) 的讨论,它(基于他网站上提供的演示)提供比 jpeg、webp 和其他一些更好的压缩。图像解码是在浏览器中用JS完成的,这意味着它可以立即使用,无需等待浏览器采用。总的来说,这似乎是一个好主意,用一些 CPU 时间换取更快的下载速度通常是一个可行的折衷方案。
技术是used here换出图像是在 window.load 上迭代 document.images,找到 src 属性包含以“.bpg”结尾的 URL 的任何位置,并将其替换为 Canvas 。
然而,这绝对不是解决问题的唯一方法,我看到了这种技术的一些缺点,其中包括:a) Canvas 与图像没有完全相同的布局规则 - 例如在其上设置宽度属性意味着在 img 与 Canvas 上有所不同,b) 至少在 Chrome 中,对于缩小与 Canvas 的图像的缩放方式似乎是不同的。
一个更好的解决方案将理想地满足这些要求:
想到的一些相关工具包括 data: 和 blob: url。
任何人都有使用这种“更好”技术加载 BPG 的工作代码示例? (Fabrice 在他的示例中使用它的方式还不错,当然方法也有取舍,但我认为可能有更好的东西可以更广泛地使用。)
最佳答案
BPG 看起来确实很有希望。如果要检测添加<img>
任何时间、任何来源的元素,您都可以使用MutationObservers .
如果您不了解它们,它们是异步的,将所有 DOM 突变的子集记录在文档中,并允许回调立即处理这些突变,而不是像 DOM 事件那样同步处理。因此,如果您在脚本中创建或更改大量图像的来源,观察者将等到您的脚本完成,然后一次性处理所有新图像(因此回调中的循环)。
以下假设您有一个名为 doSomethingToDecode(img)
的函数。 (对不起,我现在不打算提供帮助)替换 src
带有(很可能)生成的 PNG 的 img。它可以异步执行此操作,这不是问题。此外,您无需在交换 src
时停止观察图像。只要生成的替换不以“.bpg”结尾。
当您添加 <img>
时,第一个观察者会使用react任何地方的后代(和其他元素,但它忽略了那些);不幸的是,在一般情况下不可能对其进行太多优化。它必须遍历突变列表,然后是每个突变的新节点列表,因此嵌套的 for
循环。但
imgObs=new MutationObserver(
function(mutations){
for(var i=0, m; m=mutations[i]; i++) if(m.addedNodes.length)
for(var j=0, img; img=m.addedNodes[j]; j++) if(img.localName=="img"){
if(img.src && /\.bpg$/.test(img.src))
doSomethingToDecode(img)
srcObs.observe(img, srcOptions)
}
}
)
当您更改
src
时,其他观察者会使用react元素的属性,并且应该只观察 <img>
元素(为了获得最佳性能,它没有故障保护,以防你让它观察其他元素,所以不要)。srcObs=new MutationObserver(
function(mutations){
for(var i=0, m; m=mutations[i]; i++){
var img=m.target
if(img.src && /\.bpg$/.test(img.src))
doSomethingToDecode(img)
}
}
)
还要把它放在手边,每次我们开始观察新图像时都需要它:
var srcOptions={childList:false, attributes:true, attributeFilter:["src"]}
您还可以设置一个观察者,对删除
<img>
使用react。元素然后停止观察它们,并释放任何与解码相关的资源,但希望浏览器至少足够聪明,可以停止观察应该被垃圾收集的元素(未经测试!)。在加载 HTML 后运行它(不要等待带有图像和 CSS 等的整个页面)。注意:这是使用 DOM 级别 0
document.images
收藏。非常老派,但它正在做我们想要的非常有效和简洁的事情,那为什么不呢?所以首先你解码现有的
<img>
s 与 bpg 源,并观察它们是否有 src
稍后更改:for(var i=0, img; img=document.images[i]; i++){
if(img.src && /\.bpg$/.test(img.src))
doSomethingToDecode(img)
srcObs.observe(img, srcOptions)
}
然后这告诉第一个观察者对整个文档的
<body>
中的内容使用react。 ;不幸的是没有tagNameFilter
参数以 native 过滤掉非 <img>
childList 突变。imgObs.observe(document.body, {subtree:true, childList:true, attributes:false})
关于javascript - 加载bpg图片: compatible,简单高效的技巧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27586134/