天天看點

html script src屬性,動态修改script标簽中的src屬性存在的問題

今天某個同僚遇到一個詭異的問題,問題描述如下:

需求:通過腳本動态修改script标簽的src來載入一段外部腳本并執行

實作方式(#1):

document.getElementById('external-script').src='url2';

url2的内容如下:

alert('I am dynamic');

結果:

Chrome: 什麼事都沒發生(沒有請求url2)

Firefox: 什麼事都沒發生(沒有請求url2)

IE9:什麼事都沒發生(請求url2但不執行url2的腳本)

IE(6,7,8): I am dynamic(請求并執行了url2的腳本)

注意實作方式中,第一段的script标簽中間是有内容的(空格、換行符以及回車符)。

如何來解釋這個問題呢?要解釋這個問題,我們來看兩個變種的例子,第一個例子(明确内聯内容),如下所示(#2):

alert('I am inline');

document.getElementById('external-script').src='url2';

結果如下:

Chrome: I am inline(沒有請求url2)

Firefox: I am inline(沒有請求url2)

IE9:I am inline(請求url2但不執行url2的腳本)

IE(6,7,8): I am inline I am dynamic(請求并執行了url2的腳本)

再來看看第二個變種的例子(#3):

alert('I am inline script');

document.getElementById('external-script').src='url2';

其中url1的内容如下:

alert('I am url1');

結果如下:

Chrome: I am url1(沒有請求url2)

Firefox: I am url1(沒有請求url2)

IE9:I am url1(請求url2但不執行url2的腳本)

IE(6,7,8): I am url1 I am dynamic(請求并執行了url2的腳本)

首先這裡肯定的是src屬性是修改成功的,可以通過看dom的變化看到src已經設定進去了。這個時候我們比對這三個例子,思考幾十秒。分析下這三個例子,其實#2和#1是一樣的,這裡用#2是為了說明#1中的空格、換行符以及回車符會被浏覽器認為是内聯的腳本。通過比對#2和#3,是不是會讓你想到什麼?沒錯,我們第一個會想到的就是:當script标簽既有src屬性又有内聯腳本的時候浏覽器該如何處理? , 先來解釋這個問題。

一談到浏覽器應該怎樣處理,就不得不翻出各種寶典,這次不再是葵花寶典了,而是九陰真經(W3C的HTML4标準),标準中關于script标簽的src部分有如下一段話:

If the src attribute is not set, user agents must interpret the contents of the element as the script. If the src has a URI value, user agents must ignore the element's contents and retrieve the script via the URI

上面這段話的意思就是說:如果src沒有設定,那麼就執行内聯腳本,如果src設定了浏覽器就必須忽略内斂腳本而要去請求src指定的url的内容

這解釋了為什麼#3中标準浏覽器(甚至IE6,7,8)都沒有執行内聯腳本(因為src設定了url1)。

搞清楚了這個基礎問題之後,接下來問題就定位到了動态修改script的src屬性的時候浏覽器如何處理? ,從結果來看,标準的浏覽器都沒有去請求url2(更改src無效),這回IE6,7,8終于犯傻了。當然了,咱們也不能随随便便說人家犯傻,要拿出證據,這個時候繼續拿出九陰真經W3C的HTML5标準,其中有這樣一句話:

Changing the src, type, charset, async, and defer attributes dynamically has no direct effect; these attribute are only used at specific times described below.

意思就是說:修改src是沒用的,對src的處理隻會在特定的時候進行(個人猜測就是第一次看到這個屬性的時候浏覽器會去做相應處理,之後就無視它了)。

好了,這下真相大白了:這解釋了為啥#3和#1中除了IE6,7,8之外其他浏覽器都沒有去請求url2(IE9請求了,但沒執行),而且實驗發現IE6,7,8對動态修改src都會做請求執行處理。

最後,這個故事至少告訴我們:寫script标簽的時候千萬别手賤打回車。

參考文檔: