動態創建標籤:<img> VS <script>

對於統計頁面數據這樣的情景(俗稱埋點),我們常用的方式就是動態創建<img>或<script>,至於原因,一般有以下幾點:
1.埋點一般不用關心請求的結果
2.可以實現跨域請求
3.無需使用ajax就能達到發請求的目的
4.都是原生實現,兼容性好

現就兩種方式做一下對比和總結:

一、用法

1.動態創建<img>

方式1:通過img標籤

function sendByImg(src) {
    var img = document.createElement("img");
    img.src = src;
}

方式2:通過Image對象

function sendByImage(src) {
    var img = new Image();
    img.src = src;
}

2.動態創建<script>

只有一種方式:通過<script>標籤

function sendByScript(src){
    var script = document.createElement("script");
    script.src = src;
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);
}

二、區別

區別1:如果要觸發請求,動態創建的<script>必須要插入到DOM中,而動態創建的<img>則不需要

演示代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Img VS Script</title>
</head>
<body>
<h3>
    請觀察瀏覽器中的Network和Elements!
</h3>
<script>
    function sendByScript(src){
        var script = document.createElement("script");
        script.src = src;
    }

    function sendByScriptInsertDOM(src){
        var script = document.createElement("script");
        script.src = src;
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(script);
    }

    function sendByImage(src) {
        var img = new Image();
        img.src = src;
    }

    function sendByImg(src) {
        var img = document.createElement("img");
        img.src = src;
    }

    function sendRequest(src) {
        //一、通過script:
        //不插入DOM,不會觸發請求
        sendByScript(src + '/byScript');

        //插到DOM中,會觸發請求
        sendByScriptInsertDOM(src + '/byScriptDOM');


        //二、通過img:
        //不插入DOM,不會觸發請求
        sendByImage(src+ '/byImage');

        //不插入DOM,不會觸發請求
        sendByImg(src+ '/byImg');
    }

    sendRequest('https://wwww.baidu.com')

</script>
</body>
</html>

用chrome瀏覽器打開此HTML文件,查看network:
圖片描述

可以看到,插入DOM中的<script>觸發來請求,而未插入DOM中則沒有發起請求;動態創建的<img>的兩種方式沒有插入DOM,都觸發請求。

那麼問題來了,爲什麼動態創建的<script>必須要插入DOM中才會觸發請求,而動態創建的<img>則不用?
關於這個問題,在網上查了很久也沒有找到特別強有力的解釋。有人說是因爲這兩種標籤本身的特性決定的:<img>作爲展示性標籤加載的是圖片資源,其對應的地址可以直接訪問就能得到資源;<script>往往加載的是JavaScript代碼,需要網頁這樣的執行環境。個人覺得此解釋有些牽強,但也沒有找到更權威的解釋。如果有更好的觀點,歡迎留言。

區別2: 動態創建的<script>可以對請求結果進行處理,而動態創建的<img>做不到

JSONP的實現原理就是藉助動態創建<script>標籤,並對返回結果進行處理。

至此,我當時在想,那麼藉助jQuery發送JSONP請求,豈不是每發一次就要在頁面上創建一個<script>標籤?觀察結果顯示並沒有。於是去看了下jQuery的源碼:
圖片描述

如圖所示,在<script>加載完成或出錯後將標籤移除。所以,我們在用動態創建<script>方式發送請求也可以參考這種方式。

三、選擇哪種方式?

單純從發送請求的角度看,理論上兩者沒有特別大的差異,但有一點一定要注意:動態創建<img>的方式在瀏覽器禁用圖片模式下不會觸發請求

例如,在chrome瀏覽器中設置禁圖模式(設置>高級設置>隱私設置和安全性>網站設置>圖片>顯示全部 去掉),結果:
圖片描述

只有動態創建<script>的方式有請求,動態創建<img>的方式沒有任何請求記錄。

綜上,從擴展性和兼容性上看,動態創建<script>的方式是首選

四、總結

對於發送埋點請求這種應用場景,我們有兩種簡單的處理方式:動態創建<script>和<img>兩種方式,兩者最大的差異是:動態創建的<script>必須插入到DOM中才能觸發請求,而動態創建<img>的方式則不需要。但動態創建<img>的方式有個致命缺陷:瀏覽器設置了禁止圖片顯示時,無法觸發請求。所以,對於封裝埋點庫的時候,動態創建<script>的方式是首選,而且可以參考jQuery,在請求記載完成後對<script>進行清除。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章