• 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也模拟出来了。

  • 相关阅读:
    正则表达式周二挑战赛 第七周
    [译]视区百分比,canvas.toBlob()以及WebRTC
    [译]因扩展Object.prototype而引发Object.defineProperty不可用的一个问题
    [译]JavaScript需要类吗?
    [译]JavaScript中几种愚蠢的写法
    [译]JavaScript中对象的属性
    JavaScript:数组的length属性
    [译]JavaScript中的变量声明:你可以打破的三条规则
    [译]ES6:JavaScript中将会有的几个新东西
    [译]ECMAScript 6中的集合类型,第三部分:WeakMap
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/4277408.html
Copyright © 2020-2023  润新知