Non-blocking JavaScript 的問題 - IE 的 window.onload 事件

此篇文章最近更新時間為2011-02-14 06:10:56 目前共有3篇留言

關於作者 - JosephJ

任職於 Faria。喜好戶外運動、2008 年 5 月完成「跑步環島」。對於新技術跟程式碼有著強烈的偏執狂。

很讚的 Non-blocking JavaScript

前陣子將網站的所有 JavaScript 採用 Non-blocking 的方式做載入,整個介面 rendering 的時間減少很多,是我們想要的效果:

(function(){
  var scriptEl   = document.createElement("script");
  scriptEl.src   = "foo.js";
  scriptEl.type  = "text/javascript";
  scriptEl.async = true;
  document.getElementsByTagName("head")[0].appendChild(scriptEl);
}());

IE 獨有的鬼打牆問題

但是今天在 IE 發現了一個蠻嚴重的問題:「假設用 Non-blocking 的方式在 head 載入某 JavaScript ,而此 JavaScript 有指定 window 的 load 的事件處理函式,會發現它常常沒有被觸發。

IE 對 window.onload 的時間觸發點與其他瀏覽器不同

Nicholas C. Zakas 的 The truth about non-blocking JavaScript 有提到:

These three techniques for non-blocking JavaScript ensure that the downloading of the resource doesn’t block either rendering or the download of other resources on the page during page load. The little-known or understood aspect of all three approaches is that they are all defined to block the load event. That means adding scripts using any of these techniques during page load will delay execution of the window.onload event handler until all scripts have executed. All browsers obey this behavior except for Internet Explorer (even through version 9).

中文的意思是,Non-blocking 的所有方法都會對 onload 事件造成延遲、必須要等到指定的 JavaScript 讀取完畢才會真正執行,但 IE 是唯一的例外。所以在 IE 當網頁實際讀取完畢(onload)的時間點早於 JavaScript 被執行的時間點時,JavaScript 中所撰寫的 window load 事件就不會生效了...

範例網頁:除了 IE,其他瀏覽器都會跳出 alert 訊息。

所衍生的問題

看起來,似乎我們只要避免去綁 window 的 load 事件即可,但是現在的 JavaScript 函式庫大多有做一些偵測,例如我們想要當某個 div 內容讀取完畢時就做某些動作,此時便使用 YUI 的 contentready 事件,但是 contentready 事件又會去檢查 window 的 load 事件,如果剛好又滿足前段所提的條件時,我們這個 contentready 就永遠不會被觸發

目前只能先改用不會檢查 load 的 available 方法來達成,也在 YUI Forum 提出了這個問題。希望大家能夠幫我想想有沒有其他好解法。



Comments

  1. 裕波 2011-02-17 20:57:30
    我当时在使用这种方式载入js的时候,的确在ie会出现一种情况,就是发现不了对象的情况,最后只好作用try...catch 的方式来做。
  2. Hedger 2011-02-15 03:02:28
    把DomReady 跟 JSReady分開來處理,當兩者都Ready時即可吧。
  3. TonyQ 2011-02-14 23:42:01
    I just research about this one in two days. (There's somebody asking similar question in Ptt)

    The rule in jQuery might be a good consider.
    jQuery using jQuery.bindReady(); to do the job.

    I think it's a smart idea on this one.

    It store the event in jQuery.ready ,
    and check the document.readyState if document is already loaded , it fire it immediately.

    Or it will wait it.

    The benefit for to do the job is that it could hanlde the iframe onload/ajax completed as a document ready , too.

    I guess it will be a direction to check document.readyState.
暱稱: 必填。
Email: 非必填。若填寫為不公開欄位,僅供站長參考聯繫。
內容: 必填。限 255 個字元以內。
驗證碼:
送出

Facebook Comment