在做加载器时遇到一个常见问题,如何判定一个脚本已经执行完毕。

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

IE下script标签的readyState属性的更多相关文章

  1. [转]HTML5 script 标签的 crossorigin 属性到底有什么用?

    HTML5 script 标签的 crossorigin 属性到底有什么用? 最近Bootstrap 4已经正式发布了,可能已经有爱尝鲜的小伙伴在 alpha 阶段就尝试过 BS4.不过今天要说的不是 ...

  2. 怎样理解script标签的defer属性和async属性

    如果script标签是引用的外部js文件, 那就会有一个下载js文件这一过程, 为了不因为这个下载过程而阻塞页面解析与渲染, 我们需要一种机制来解决这一问题, 方法之一就是使用 defer和async ...

  3. html中script标签使用async属性和defer属性的区别

    相同点: 首先async和defer只对header里的外连脚本script标签上起作用,如果script标签是放在header外或者是header里的内置脚本以及动态生成的script标签是不起作用 ...

  4. script标签不带属性与带async、defer的区别

    <script> 当页面解析到script标签时,会停止解析并下载对应的脚本,并马上执行,执行完毕后再继续解析页面 <script async> async 在下载脚本的同时不 ...

  5. script标签的crossorigin属性

    通常我们使用window.onerror来捕获js脚本的错误信息. 但是对于跨域调用的js脚本,onerror事件只会给出很少的报错信息:error: Script error. 这个简单的信息很明显 ...

  6. select标签下option标签里value属性有什么用以及和text的区别

    转自:http://blog.csdn.net/summer_sy/article/details/54572398 1:value的用处 <select > <option val ...

  7. script标签属性sync和defer

    <script src="a.js" defer></script> 加了defer属性script标签的页面,运行流程如下:   1.浏览器开始解析HTM ...

  8. 如何将 JavaScript 代码添加到网页中,以及 <script> 标签的属性

    Hello, world! 本教程的这一部分内容是关于 JavaScript 语言本身的. 但是,我们需要一个工作环境来运行我们的脚本,由于本教程是在线的,所以浏览器是一个不错的选择.我们会尽可能少地 ...

  9. script标签crossorigin属性及同源策略和跨域方法

    首先介绍(同源策略) 同源策略是浏览器最核心且基本的安全约定,要求协议.域名.端口都相同为同源,如果非同源时请求数据浏览器会在控制台抛出跨域异常错误,同源策略是浏览器的行为,即使客户端请求发送了,服务 ...

随机推荐

  1. Nginx 学习笔记(二)Web 服务启用 HTTP/2

    个人网站提升为HTTP2.0协议,加速访问 一.条件 1.openssl的版本必须在1.0.2e及以上 2.nginx的版本必须在1.9.5以上 二.编译安装 1.openssl 编译安装 (1)开始 ...

  2. 微信现金红包 python

    微信现金红包发送接口,好像没法限制一个用户一个活动只能领取一次红包,在调用红包接口上,自己做了限制 REDPACK_RECORD 建表sql -- Create table create table ...

  3. 正方体旋转demo

    接着上一篇博客的内容顺藤摸瓜往下想,既然stage有景深这个概念,可以表达3D场景,那么这个stage就可以呈现立体几何咯,于是自己写了个Cubic Demo 一个正方体有6个面,我们把一个正方体平铺 ...

  4. 微信开发创业交流QQ群列表

    方倍工作室参与或主导的微信相关的QQ社群列表,欢迎对照加入. QQ群号 群名称 说明 推荐 518924126 微信平台开发有问必答 知识付费  ★★★★★ 188280503 微信公众平台开发最佳实 ...

  5. Java SE之装箱与拆箱【基本数据类型的包装类/==与equals方法】

     对象包装器.自动装箱与拆箱   2016/11/30  晚   特点       1.所有的基本类型都有一个包装器类与之对应.[Integer,Boolean,Long,Character,Shor ...

  6. Debian 无线网卡驱动问题

    参考这里:https://wiki.debian.org/iwlwifi Debian 9 "Stretch" Add a "non-free" compone ...

  7. Linux定时任务调度

    ⒈概述 任务调度:是指系统在某个时间执行的特定的命令或程序 分类:1)系统任务:有些重要的工作必须周而复始的执行,例如病毒扫描等 2)用户任务:个别用户可能希望定时执行某些程序,例如mysql定时备份 ...

  8. 【Python】JBOSS-JMX-EJB-InvokerServlet批量检测工具

    一.说明 在JBoss服务器上部署web应用程序,有很多不同的方式,诸如:JMX Console.Remote Method Invocation(RMI).JMXInvokerServlet.Htt ...

  9. Linux内存管理1---内存寻址

    1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...

  10. 基于内容的图片检索CBIR简介

    原文地址:http://blog.csdn.net/davebobo/article/details/53171311 传统的图像检索过程,先通过人工对图像进行文字标注,再利用关键字来检索图像,这种依 ...