本文首發於公衆號:符合預期的CoyPan
瀏覽器在何時會去加載一張圖片呢?固然是咱們網頁中有圖片的時候。在平時的項目開發中,咱們還經常會用圖片進行日誌上報,大概像下面這樣:javascript
var img = new Image(); img.src = 'http://上報地址?a=1'
新建一個Image,將其src賦值,瀏覽器便會發出一個網絡請求。html
再來考慮一下下面的代碼:java
var scriptEl = document.createElement('script'); scriptEl.src = 'http://xxxx.js';
上面的代碼會發起網絡請求麼?canvas
答案是:不會。只須要增長一行代碼,將script插入到DOM樹中,便會觸發網絡請求。瀏覽器
var scriptEl = document.createElement('script'); scriptEl.src = 'http://xxxx.js'; document.body.appendChild(scriptEl); // 這行代碼會觸發請求
再來看下面的代碼:網絡
var imgStr = '<img src="xxx.png">'; var divEl = document.createElement('div'); divEl.innerHTML = imgStr;
上面的代碼會觸發網絡請求麼?答案是:會的。雖然divEl並無被插入到DOM樹中,可是網絡請求依然會觸發。這種表現一開始是讓我有點意外的。因而乎,我開始了探索。app
翻了一下html規範,發現了下面這段話:函數
地址:https://html.spec.whatwg.org/...spa
大概的意思就是:prototype
若是瀏覽器禁用了js腳本,那麼瀏覽器能夠當即請求圖片,也能夠根據須要加載圖片。若是瀏覽器沒有禁用js腳本,當img元素被建立,或者經歷一些變化(src被賦值等) 時,瀏覽器必須當即進入一個update the image data的流程。在update the image data這個流程中,若是圖片元素尚未內容,而且圖片元素的src已被賦值,瀏覽器會當即發起請求去請求圖片。
這樣,就能夠解釋上述的現象了:
Case 1
var img = new Image(); img.src = 'http://上報地址?a=1' // Object.prototype.toString.call(img) === "[object HTMLImageElement]"
使用Image構造函數時,生成了一個HTMLImageElement
實例,也就是一個img元素,而後給這個img元素的src賦了值。很顯然,咱們使用了javascript。按照規範,瀏覽器必須當即發起網路請求,更新圖片數據。
Case 2
var imgStr = '<img src="xxx.png">'; var divEl = document.createElement('div'); divEl.innerHTML = imgStr; // Object.prototype.toString.call(divEl.firstChild) === "[object HTMLImageElement]"
在使用了innerHTML後,其實咱們也是生成了一個HTMLImageElement
實例。按照規範,瀏覽器也必須當即發起網絡請求,更新圖片數據。
總結一下:只要咱們在代碼中建立了一個img元素(HTMLImageElement實例),而且咱們給這個img元素的src賦值了,那麼瀏覽器就會發起網絡請求,加載圖片內容。
咱們再來規範裏是怎麼規定script標籤的。
地址:https://html.spec.whatwg.org/...
在script標籤的相關規範裏,我沒有找到明確的說明在什麼狀況下須要發起網絡請求加載資源。另外,我看到了上面紅框裏的這段話。歸納一下,就是:
瀏覽器能夠在設置script元素的src時候,就發起網絡請求加載資源。可是若是最後,這個script元素沒有插入DOM的話,網絡請求就徹底被浪費了。
能夠理解爲:瀏覽器能夠在設置script元素的時候,自行考慮是否須要當即發起網絡請求加載資源。而後瀏覽器在實現的時候,爲了節約資源,並無當即發起請求,而是選擇了在插入DOM樹後,才發起請求。
(這裏不是很肯定,可是沒有找到更進一步的說明)
不考慮規範,在平時的業務中,咱們新建圖片後,無論圖片是否最終插入DOM樹,都須要當即拿到圖片的信息,好比canvas,好比經過圖片的寬高進行頁面排版等。所以,新建img元素後當即發起請求拿到圖片數據,是合乎邏輯的。
對於script元素來講,也不存在須要單獨操做的場景,爲了節省資源,script插入DOM樹後再發起網絡請求,也是合乎邏輯的。
在業務開發中,某些代碼看起來很理所固然,便沒有多想。偶爾會遇到讓人意外的表現,這個時候探索一下,加深一下理解,也算是符合預期吧。