img.onload 思考

是這樣的,今天群里基友發了張截圖

Paste_Image.png
Paste_Image.png

研究一下

1.頁面渲染過程

這個標題下的內容很適合做這篇文章的導讀

下面這張圖是webkit渲染過程


Paste_Image.png
Paste_Image.png

雖然是渲染過程,但能了解到圖片資源的加載是瀏覽器通過圖片加載器異步請求獲取的。

2.代碼執行情況

javascript是單線程序解釋器,一定時間內只能執行一段代碼。

  • 同步執行的任務放到主線程按加入順序執行
  • 異步任務扔到任務隊列,主線程執行完之后會從任務隊列里按照先入先出的方式取任務(忽略些細節)

setTimeout和setInterval創建的都是異步任務,扔到任務隊列,接受的第二個參數意思是再過多久取消等待狀態。里面的定時/間歇回調執行的條件是

1?? 主線程任務執行完畢
2?? 任務隊列里輪到你了:你前面沒別人了 或者 你前面有人但是他條件不足 仍處于等待執行狀態
3?? 你的等待狀態為 可以執行 了

有上述3個執行條件加上一些瀏覽器默認設置,比如最小設置時間數,立即執行的毫秒數不是0等限制和實現的不同,嚴格執行是個夢。
尤其是setInterval容易發生后一個調用在前一個調用結束前啟動。
so 先改成標準的間歇使用方式。

var img = new Image();
var timesize = 20;
img.onload = function(){//事件注冊程序扔到任務隊列-DOM0級事件注冊方法
    console.log("事件上鉤了!圖片已load:"+img.height)
}

function fixTimer () {
    if(!!!img.height){
        console.log("沒買著繼續排隊")
        setTimeout(fixTimer,timesize);//扔到任務隊列
    }else{
        console.log("買到啦回家!:"+img.height)
        console.log("定時器 done")
    }
}
img.src = "http://7jpswm.com1.z0.glb.clouddn.com/transitionSnip20160122_155.png"http://ImageLoader-瀏覽器資源異步加載

setTimeout(fixTimer,timesize);//扔到任務隊列

預測執行結果

讀過紅寶書的一定看到過這段話:

新圖像元素不一定從添加到文檔后才開始下載,只要設置了src屬性就會開始下載

為什么?
因為src一旦設置,瀏覽器就把活搶走了,開始調用ImageLoader來加載圖片,而且是瀏覽器行為
如代碼所示
任務隊列第一個是事件處理程序onload
任務隊列第二個是定時任務setTimeout

當主線程沒任務時 有三條時間線
1?? javascript 主線程輪詢任務隊列過程:有沒有可執行的 取決于 等待狀態 解鎖條件
2?? ImageLoader 資源請求過程:時間取決于圖片大小 網絡狀況
3?? 圖片資源下載完成的時間:決定解鎖 事件處理程序的執行

第一種情況

  • 主線程執行完
  • 圖片有點大 網還有點慢 還沒請求到
  • 事件處理程序 準備好了嗎?no
  • setTimeout 到時間了嗎? yes 執行 獲取到圖片高度了嗎 no 繼續創建一個扔到隊列
  • 圖片請求到了 也下載完了
  • 事件處理程序 準備好了嗎? yes 執行
  • setTimetout 到時間了嗎?yes 執行 獲取到圖片高度了嗎 yes done

這種情況輸出為

沒買著繼續排隊
事件上鉤了!圖片已load
買到啦回家!

第二種情況

  • 主線程執行完
  • 圖片小 網絡快 一下就請求到 下載完了
  • 事件處理程序 準備好了嗎? yes 執行
  • setTimetout 到時間了嗎?yes 執行 獲取到圖片高度了嗎 yes done

這種情況輸出為

事件上鉤了!圖片已load
買到啦回家!

實際代碼跑例

Paste_Image.png
Paste_Image.png

第三種情況

  • 主線程執行完
  • 圖片大 還沒請求到
  • 事件處理程序 準備好了嗎? no 不執行
  • setTimetout 到時間了嗎?yes 執行 獲取到圖片高度了嗎 no 繼續排著
  • 圖片大 還沒請求到
  • 事件處理程序 準備好了嗎? no 不執行
  • 圖片大 但是嘎嘣就請求到了
  • setTimetout 到時間了嗎?yes 執行 獲取到圖片高度了嗎 yes 不用排了
  • 事件處理程序 準備好了嗎? yes 執行
    輸出為
沒買著繼續排隊
買到啦回家!
事件上鉤了!圖片已load

實際代碼跑例 換了個大圖

Paste_Image.png
Paste_Image.png

這里面你還可以加入 圖片大 請求到了 但是還沒下載到的情況分析 請看下圖

Paste_Image.png

只有content download才會觸發通知事件

總結

其實還有幾種情況 比如主線程存在阻塞、定時任務中存在同步阻塞等
不過 本篇想說明的是

由于代碼運行環境的特殊性 忽略基本實現和協作實現 會造成遺漏或者不可預測的運行結果
比如這里
基本實現——瀏覽器內js的運行機制
協作實現——就是瀏覽器的資源加載器

補充

  • 2016-11-14

圖片下載時在沒有禁用緩存或者沒有加請求隨機變量的情況下 會緩存。
當圖片被緩存時是無法觸發onload的。
這時候可以用img.complete來做圖片準備好觸發回調的邏輯。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個最簡單的問題,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,831評論 1 17
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,366評論 11 349
  • GCD簡介 GCD 是 libdispatch 的市場名稱,而 libdispatch 作為 Apple 的一個庫...
    獨木舟的木閱讀 1,292評論 0 5
  • 等,斜斜的殘陽慢慢消失 看,藹藹的暮色沉沉落下 聽,知了的歌聲響徹山谷 笑,大黃狗啃著骨頭奔跑 說,新舊故事都娓娓...
    螢染閱讀 290評論 2 1