DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> 關於圖片的預加載過程中隱藏未知的
關於圖片的預加載過程中隱藏未知的
編輯:關於JavaScript     
看完了曼聯與曼城的同城德比,還有漫長的兩個小時,才能看到期待中的國家德比。無聊的很,左右無事,便來論壇閒逛。看到了一章關於圖片預加載的博文,其代碼如下:
復制代碼 代碼如下:
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的調用。
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved