IE下script標簽的readyState屬性


在做加載器時遇到一個常見問題,如何判定一個腳本已經執行完畢。

  • “uninitialized” – 原始狀態
  • “loading” – 下載數據中
  • “loaded” – 下載完成
  • “interactive” – 還未執行完畢
  • “complete” – 腳本執行完畢.

網上流行的答案是這個,我怎么覺得其實這是抄自XMLHttpRequest的readyState呢?!恰逢這兩個都有這屬性。

我們親自做一個實驗:

<!DOCTYPE html>
<html>
    <head>
        <title>node.readyState</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <script>
            var node = document.createElement("script")
            node.onreadystatechange = function() {
                var state = node.readyState
                setTimeout(function() {
                    var div = document.createElement("div")
                    document.body.appendChild(div)
                    div.innerHTML = state
                }, 300)

            }
            var head = document.getElementsByTagName("head")[0]
            head.appendChild(node)
            node.src = "avalon.js"

        </script>
    </head>
    <body>
        <div>node.readyState</div>
    </body>
</html>

完整的控件教程
IE11 空白,說明完全與標准一致了
IE10 loading loaded
IE9 loading loaded
IE8 complete loaded
IE7 complete loaded 但有一定機率,只出現complete或loaded
IE6 complete loaded 但有一定機率,只出現complete或loaded

換言之,IE67是個非常悲催的問題。另外,opera9-10也支持readyState,根據老外的描述,它竟然兩次都是loaded!

因此我們需要根據瀏覽器的情況采用不同的策略。

首先是使用何種回調,如果是支持onload事件,那么就直接用onload 就沒有這么多麻煩事。最簡單的策略是這樣判定:

        var node = DOC.createElement("script")
        var supportLoad = "onload" in node
        var onEvent = supportLoad ? "onload" : "onreadystatechange"
        node[onEvent] = callback

判定完成時機, 我們不使用網上的/complete|loaded|undefined/.test(node.readyState),這會同時掉進opera與IE67的坑中。對於使用onload事件進行監聽的,不再判定node.readyState,IE(其實也就是IE6-8),需要使用一個定時器。當第一次進行onreadystatechange回調時,timeID為空, 並且readyState為complete或loaded時,我們設置它在300ms后再執行自身。然后如果瀏覽器還執行此回調時, 它就進入第二個分支,清掉定時器,執行用戶代碼。萬一,瀏覽器只執行一次onreadystatechange回調,那也沒關系,讓定時器100~300ms后執行用戶代碼

最后貼出全部代碼:

        //通過script節點加載目標模塊
        var node = DOC.createElement("script")
        var timeID
        var supportLoad = "onload" in node
        var onEvent = supportLoad ? "onload" : "onreadystatechange"
        node[onEvent] = function onLoad() {
            if (!supportLoad && !timeID && /complete|loaded/.test(node.readyState)) {
                timeID = setTimeout(onLoad)
                return
            }
            if (supportLoad || timeID) {
                clearTimeout(timeID)
                //你的代碼
            }
        }

        head.insertBefore(node, head.firstChild) //chrome下第二個參數不能為null
        node.src = url //插入到head的第一個節點前,防止IE6下head標簽沒閉合前使用appendChild拋錯

大家也可以到這里看一下它的實際應用,如果大家都是使用AMD規范定義JS文件,那么我在舊式IE下連onerror也模擬出來了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM