首頁 >web前端 >js教程 >關於圖片的預先載入過程中隱藏未知的_javascript技巧

關於圖片的預先載入過程中隱藏未知的_javascript技巧

WBOY
WBOY原創
2016-05-16 17:46:14886瀏覽

看完了曼聯與曼城的同城德比,還有漫長的兩個小時,才能看到期待中的國家德比。無聊的很,左右無事,便來論壇閒逛。看到了一個關於圖片預先載入的博文,其程式碼如下:

複製程式碼 程式碼如下:

function loadImage(url, callback) {
var img = new Image(); //建立一個Image對象,實作圖片的預先下載
img.src = url;
if (img. complete) { // 如果圖片已經存在於瀏覽器緩存,直接調用回調函數
callback(img);
return; // 直接返回,不用再處理onload事件
}
img. onload = function () { //圖片下載完畢時非同步呼叫callback函數。
callback(img);
};
};

在網路上搜尋了一下相關文章,大體上都是這個思路。
這個方法功能是ok的,但是有些隱憂。
1 建立了一個臨時匿名函數來作為圖片的onload事件處理函數,形成了閉包。
相信大家都看過ie下的記憶體洩漏模式的文章,其中有一個模式就是循環引用,而閉包就有保存外部運行環境的能力(依賴於作用域鏈的實現),所以img. onload這個函數內部又保存了對img的引用,這樣就形成了循環引用,導致記憶體洩漏。 (這種模式的記憶體洩漏只存在低版本的ie6中,打過補丁的ie6以及高版本的ie都解決了循環引用導致的記憶體洩漏問題)。

2 只考慮了靜態​​圖片的加載,忽略了gif等動態圖片,這些動態圖片可能會多次觸發onload。
要解決上面兩個問題很簡單,其實很簡單,程式碼如下:
複製程式碼 程式碼如下:

img.onload = function () {
//圖片下載完畢時非同步呼叫callback函數。
img.onload = null;
callback(img); };

這樣既能解決記憶體洩漏的問題,又能避免動態圖片的事件多次觸發問題。
在一些相關部落格文章中,也有人注意到了要把img.onload 設為null,只不過時機不對,大部分文章都是在callback運行以後,才將img.onload設為null,這樣雖然能解決循環引用的問題,但是對於動態圖片來說,如果callback運行比較耗時的話,還是有多次觸發的隱患的。
隱憂經過上面的修改後,就消除了,但這個程式碼還有最佳化的空間:
複製程式碼 程式碼如下:

if (img.complete) {
// 如果圖片已經存在於瀏覽器緩存,直接呼叫回調函數
callback(img);
return; / / 直接返回,不用再處理onload事件
}

關於這段程式碼,看相關博文裡的敘述,原因如下:
經過對多個瀏覽器版本的測試,發現ie、opera下,當圖片載入過一次以後,如果再有對該圖片的請求時,由於瀏覽器已經快取住這張圖片了,不會再發起一次新的請求,而是直接從快取中加載過來。對於firefox和safari,它們試圖使這兩種載入方式對使用者透明,同樣會引起圖片的onload事件,而ie和opera則忽略了這種同一性,不會引起圖片的onload事件,因此上邊的程式碼在它們裡邊不能得以實現效果。

確實,在ie,opera下,對於快取圖片的初始狀態,與firefox和safari,chrome下是不一樣的(有興趣的話,可以在不同瀏覽器下,測試一下在給img的src賦值快取圖片的url之前,img的狀態),但是對onload事件的觸發,卻是一致的,不管是什麼瀏覽器。產生這個問題的根本原因在於,img的src賦值與 onload事件的綁定,順序不對(在ie和opera下,先賦值src,再賦值onload,因為是緩存圖片,就錯過了onload事件的觸發)。應該先綁定onload事件,然後再給src賦值,代碼如下:
複製代碼 代碼如下:

function loadImage(url, callback) {
var img = new Image(); //建立一個Image對象,實作圖片的預先下載
img.onload = function(){
img .onload = null;
callback(img);
}
img.src = url;
}
這樣記憶體洩漏,動態圖片的載入問題都得到了解決,而且也以統一的方式,實作了callback的呼叫。
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn