2013-11-23 24 views
0

下面的代碼將註冊一個的onerror功能用於在圖像元件的JavaScript img.onerror改變源 - 競爭條件

(function() { 

    var imgElements = document.getElementsByTagName('img'); 
    for(i = 0; i < imgElements.length; i++) { 
     (function() { 

        imgElements[i].onerror = function() { 
         this.src = base_url() + 'assets/images/placeholder.jpg'; 
        } 


     })(); 
    } 

})(); 

此代碼的工作只是有時。 (我使用鉻);如果我按住F5或非常快地刷新頁面,看起來像onerror函數沒有得到執行。

例如:如果我加載頁面,然後等待幾秒鐘,並再次刷新src會改變,但不是所有的時間。

我相信這是瀏覽器的某種類型的緩存問題?

更具體地說,如果我按下chrome上的刷新圖標,即使突然刷新,一切都會正常工作。

但是,如果我突出顯示URL並按回車鍵,則代碼不會最終將src更改爲佔位符圖像。

您能否告訴我爲什麼會發生這種情況,並提出一種解決方法?

+0

您正在使用'i',但它不是一個閉包變量,因此它將包含循環中的最後一個值。 – Barmar

+0

我已經改變它傳遞對象'imgElements [i]',它仍然導致相同的功能。 –

+0

其實,這不相關。你沒有在回調函數中使用'i'。我不明白你爲什麼把所有這些IIFE放在首位,他們只是讓代碼更加混亂。 – Barmar

回答

2

您無法控制事情的時機,以這種方式可靠地按照您嘗試這樣做的方式進行工作。這裏的秩序的事情發生了:

  1. 瀏覽器獲取的HTML頁面
  2. 瀏覽器開始解析HTML
  3. 它找到一個<img>標籤,它觸發關閉加載src URL的請求。
  4. 瀏覽器發現src URL無法加載,從而觸發onerror處理程序。
  5. 您的JavaScript運行並安裝onerror處理程序。

現在,步驟4和步驟5的順序完全與時間有關並且不受您的控制。有些情況可能會導致它按照這種順序發生,而4和5的某些情況則會發生逆轉。並且請記住,一旦您的頁面被加載一次,其中的一部分可能會被緩存,並且後續加載中的時序可能會有所不同。某些瀏覽器甚至可能緩存URL當前無法訪問的事實,並且如果它立即再次請求(從而生成立即的錯誤響應),則可能會避免再次嘗試它。

此外,當.src屬性設置爲新值時,某些瀏覽器的行爲完全不正確。幾年前,我知道某些瀏覽器在更改.src屬性並加載新映像時並未可靠地觸發onload事件。對於onerror處理程序也是如此。我的經驗是,他們可以可靠地爲第一次圖像加載工作,但我不確定他們在設置不同的.src屬性時可靠地工作。

要設置一個不會錯過的錯誤處理程序,必須在.src屬性被設置或解析之前使用它。這有兩種方法可以做到這一點。

  1. 將使用onerror處理程序的HTML本身,以便它是<img>標籤的一部分。
  2. 在您的HTML中沒有完全形成<img>標籤(例如,src或不在HTML中),然後用你的javascript,你可以添加onerror處理程序,然後創建圖像或適當地設置.src

關鍵是onerror處理程序必須在以任何方式設置.src屬性之前安裝。

解決方案#1是這樣的:實現的解決方案#2

<img src="xxx.jpg" onerror="setErrorImage(this)"> 

// this function must be in the global scope 
function setErrorImage(img) { 
    // clear error handler so no chance of looping 
    img.onerror = function() {}; 
    img.src = base_url() + 'assets/images/placeholder.jpg'; 
} 

一種方法是這樣的:

<img data-src="xxx.jpg"> 

(function() { 
    function setErrorImage() { 
     this.removeEventListener("error", setErrorImage); 
     this.src = base_url() + 'assets/images/placeholder.jpg'; 
    } 

    var imgElements = document.getElementsByTagName('img'); 
    var img, url; 
    for (var i = 0; i < imgElements.length; i++) { 
     img = imgElements[i]; 
     // now that onerror handler is in place, set the .src property 
     url = img.getAttribute("data-src") 
     if (!img.src && url) { 
      img.addEventListener("error", setErrorImage); 
      img.src = url; 
     } 
    } 
})(); 

你也可以沒有<img>標籤在HTML不惜一切創造所有這些動態通過JavaScript動態,確保在設置.src屬性之前安裝了onerror處理程序,但這往往會使設計過程更復雜一些。對於選項#2,上述解決方案通常優先於完全以代碼形式創建圖像對象。

+0

修改後的代碼更加健壯。 – jfriend00