![](/img/trans.png)
[英]Techniques for loading page with several thumbnail images (laravel 5.3)
[英]loading bpg images: compatible, simple and efficient techniques
最近有一些關於Fabrice Bellard的BPG圖像格式( http://bellard.org/bpg/ )的喧嘩,基於他網站上提供的演示,它提供了比jpeg,webp和其他一些更好的壓縮。 圖像解碼在瀏覽器中使用JS完成,這意味着它可以立即使用,無需等待瀏覽器采用。 總的來說,這似乎是一個好主意,並且為了更快的下載而交換一些CPU時間通常是可行的權衡。
這里用於交換圖像的技術是在window.load上迭代document.images,找到src屬性包含以“.bpg”結尾的URL的任何位置,並用畫布替換它。
然而,這絕對不是解決問題的唯一方法,我看到這種技術的一些缺點,包括:a)畫布與圖像沒有完全相同的布局規則 - 例如,設置寬度屬性就意味着不同的東西在img vs a canvas上,b)似乎至少在Chrome中,對於縮小與畫布相比的圖像,縮放是如何進行的。
理想情況下,更好的解決方案可滿足這些要求
想到的一些相關工具包括data:和blob:urls。
任何人都有使用這種“更好”技術加載BPG的工作代碼示例? (Fabrice在他的例子中使用它的方式也不錯,當然方法有權衡,但我認為可能有更好的廣泛使用。)
BPG確實看起來很有前景。 如果要隨時從任何來源檢測到<img>
元素的添加,可以使用MutationObservers 。 如果您不了解它們,它們是異步的,記錄文檔中所有DOM突變的子集,並允許回調一次處理這些突變,而不是像DOM事件那樣同步。 因此,如果您在腳本中創建或更改大量圖像的來源,觀察者將等待您的腳本完成,然后一次性處理所有新圖像(因此回調中的循環)。
以下假設您有一個名為doSomethingToDecode(img)
的函數(抱歉,我現在不會幫助它),它將(很可能)生成的PNG替換為img的src
。 它可以異步執行,這不是問題。 此外,只要生成的重新加入不以“.bpg”結尾,您就不需要在交換src
時停止觀察圖像。
當你在任何地方添加<img>
后代時,第一個觀察者會做出反應(而其他元素卻會忽略它們); 遺憾的是,在一般情況下不可能對其進行大量優化。 它必須迭代突變列表,然后迭代每個突變的新節點列表,因此嵌套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
屬性時,另一個觀察者會做出反應,並且應該只觀察<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>
元素的刪除作出反應,然后停止觀察它們,並釋放任何與解碼相關的資源,但希望瀏覽器至少足夠聰明,可以停止觀察應該被垃圾收集的元素(不是測試!)。
加載HTML后運行此命令(不要等待整個頁面包含圖像和CSS等)。 注意:這是使用DOM級別0 document.images
集合。 非常老派,但它正在非常有效和簡潔地完成我們想要的,所以為什么不呢?
首先,您使用bpg源解碼現有的<img>
,並在以后觀察它們的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>
中的東西作出反應; 遺憾的是,沒有tagNameFilter
參數來本地過濾掉非<img>
childList突變。
imgObs.observe(document.body, {subtree:true, childList:true, attributes:false})
向圖像添加錯誤事件處理程序。 在Chrome 40上,當圖像丟失或瀏覽器不知道如何顯示時會觸發它:
<script>
var errors = [];
function fallback(elt) {
if(errors[elt.src]) return;
// you should also extract the extension in order to test lena.bpg, lena.png, lena.jpg and not lena.bpg.png, lena.bpg.png.jpg
errors[elt.src] = true;
console.error('could not load image, falling back');
elt.src = elt.src + '.png';
// stop trying
elt.onerror= function(){};
}
</script>
<img src="test.html" onerror="fallback(this);" width=300 height=300 />
優點:客戶端部分沒有內存/ CPU使用情況。 缺點:需要在服務器上提供備用圖像。
我相信你可以在所有img
標簽上聲明一個全局錯誤監聽器,這樣這對於將來的圖像也是如此。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.