一、应用场景:

有时候我们需要动态创建script标签实现脚本的按需加载,我们会为script标签绑定onload或者onreadystatechange事件,用于检测动态脚本是否加载并执行完毕,在事件处理程序中引用动态脚本创建的变量。

二、问题描述:

如果我们动态创建script标签并绑定事件处理程序后,立即移除script标签,那么事件处理程序是否会执行?如果能执行,那么能否正常引用动态脚本创建的变量?

三、看如下程序:

function inviteFriends() {
var self = this; if ($("#onlineserviceMailToFriend").size() > 0) {
showMail();
} else {
var jsUrl = "http://images.139cm.com/mpost2014/js/mpost/onlineservice/m2012.mpost.onlineservice.view.mailtofriend.js?v=1.0"; // 动态创建script标签加载脚本
M139.core.utilCreateScriptTag({
id : "onlineserviceMailToFriend",
src : jsUrl,
charset : "utf-8"
}, showMail);
} // 异步请求脚本之后马上移除script标签
$("#onlineserviceMailToFriend").remove(); // script标签的onload或onreadystatechange事件处理程序
function showMail() {
if (!self.mailToFriend) {
// IE系列会报错找不到对象:M2012.Mpost.OnlineService.View.MailToFirend
// chrome浏览器可正常运行
self.mailToFriend = new M2012.Mpost.OnlineService.View.MailToFirend({
model : self.model
});
}
self.mailToFriend.render();
}
}
/**
*动态加载script标签
*@param {Object} options 配置
*@param {Stirng} options.id script标签的id ;
*@param {Stirng} options.src JS文件地址(完整路径);
*@param {Stirng} options.charset 给script标签加charset属性
*@param {Function} callback 加载完成的回调
*@example
*M139.core.utilCreateScriptTag(
{
id:"examplejs",
src:"http://images.139cm.com/m2012/richmail/js/example.js",
charset:"utf-8"
},
function(){
alert("文件加载完毕");
}
*);
*/
function utilCreateScriptTag(options, callback) {
var This = this;
if (callback) {
var _callback = callback;
var callback = function() {
_callback.call(This);
}
}
var scriptId = options.id;
var dataHref = this.getScriptPath(options.src);
var charset = options.charset;
var isReady = false;
var head = document.getElementsByTagName("head")[0];
var objScript = scriptId && document.getElementById(scriptId);
//是否移出脚本DOM(非IE9时处理)
var isRemoveScriptDom = !document.all && true || false, browserVersion = ["msie 10.0", "msie 9.0", "chrome", "firefox"], i = 0, bvLenght = browserVersion.length - 1, currVersion = window.navigator.userAgent.toLowerCase() || "";
//IE9、chrome、firefox时处理
while (i <= bvLenght) {
isRemoveScriptDom = currVersion.indexOf(browserVersion[i]) > -1 && true || false;
if (isRemoveScriptDom) {
break;
}
i++;
}
browserVersion = null;
try {
if (objScript && isRemoveScriptDom) {
objScript.src = "";
objScript.parentNode.removeChild(objScript);
objScript = null;
}
} catch (e) {
}
if (objScript != null) {
if (dataHref.indexOf("?") == -1)
dataHref += "?";
dataHref += "&" + Math.random();
objScript.src = dataHref;
var dataScript = objScript;
} else {
var dataScript = document.createElement("script");
if (scriptId) {
dataScript.id = scriptId;
}
if (charset) {
dataScript.charset = charset;
}
try {
if (dataHref.indexOf("?") == -1) {
dataHref = M139.Text.Url.makeUrl(dataHref, {
sid : top.$App.getSid()
});
}
} catch (e) {
}
dataScript.src = dataHref;
dataScript.defer = true;
dataScript.type = "text/javascript";
head.appendChild(dataScript);
}
if (document.all) {
dataScript.onreadystatechange = function() {
if (dataScript.readyState == "loaded" || dataScript.readyState == "complete") {
isReady = true;
if (callback)
callback();
}
}
} else {
dataScript.onload = function() {
isReady = true;
if (callback)
callback();
}
dataScript.onerror = function() {
isReady = true;
if (callback)
callback();
}
}
}

四、结论:

由于函数utilCreateScriptTag是通过属性赋值的方式注入事件处理程序,而移除脚本调用的是jQuery的remove方法,dom虽然移除但事件依然存在于内存,所以当浏览器加载脚本并执行完毕,事件处理程序依然会被调用,这一点IE浏览器与标准浏览器表现一致,但是当试图在事件处理程序中引用动态脚本创建的变量时,IE系列无一例外的报错,而标准浏览器却可以正常引用。

移除script标签引起的兼容性问题的更多相关文章

  1. JavaScript之<script>标签简介

    向html页面中插入JavaScrpt的主要方法,就是使用<script>元素,下面是Html 4.01为<script>定义的6个属性. 1.async:可选表示应该立即下载 ...

  2. script标签

    script 元素既可以包含脚本语句,也可以通过 src 属性指向外部脚本文件.默认情况下script标签的会阻止文档渲染,相关脚本会立即下载并执行. 属性 在HTML5中script主要有以下几个属 ...

  3. script标签加载顺序(defer & async)

    script 拥有的属性 async:可选,表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本.只对外部脚本文件有效. charset:可选.表示通过 src 属性指 ...

  4. [转]Script标签和脚本执行顺序

    Script标签和脚本执行顺序 这里详细聊聊和script标签相关的脚本执行顺序. Script标签的默认行为 几个首要特性: script标签(不带defer或async属性)的会阻止文档渲染.相关 ...

  5. [译]我们应该在HTML文档中何处放script标签

    本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...

  6. javaScript中的小细节-script标签中的预解析

    首先介绍预解析,虽然预解析字面意思很好理解,但是却是出坑出的最多的地方,也是bug经常会有的地方,利用好预解析的特性可以解决很多问题,并且提高代码的质量及数量,浏览器在解析代码前会把变量的声明和函数( ...

  7. script标签中defer和async属性的区别

    这篇文章来源于JS高级程序设计第三版中关于script标签的介绍,结合查阅的资料写下的学习笔记. 向html页面中插入javascript代码的主要方法就是通过script标签.其中包括两种形式,第一 ...

  8. HTML 5 <script> 标签

    HTML 4.01 与 HTML 5 之间的差异 async 属性是 HTML 5 中的新属性. 在 HTML 5 中,不再支持 HTML 4.01 中的一些属性. 提示和注释 注释:脚本按照如下方式 ...

  9. script标签里的defer属性

    入职新公司,看代码的时候注意到有的script标签中有一个defer属性,查了一下.在这里分享出来. 需要注意的有三点,其中前两点是在错误中分辨出来的: 错误来源:http://www.w3schoo ...

随机推荐

  1. ubtuntu 如何查看内存用量 mongostat详解

    free -h top free或者top或者cat /proc/meminfo mongostat是mongdb自带的状态检测工具,在命令行下使用.它会间隔固定时间获取mongodb的当前运行状态, ...

  2. 从pg_hba.conf文件谈谈postgresql的连接认证

    最近一直在弄postgresql的东西,搭建postgresql数据库集群环境什么的.操作数据库少不得要从远程主机访问数据库环境,例如数据库管理员的远程管理数据库,远程的客户存取数据库文件. 而在po ...

  3. redis持久化以及集群

    redis提供了两种持久化策略:RDB与AOF RDB RDB的持久化策略: 按照规则定时将内存的数据同步到磁盘 snapshot(按照快照方式完成,当条件符合redis某一种规则,将内存数据写入磁盘 ...

  4. Tomcat 配置文件的解析

    转载:https://www.cnblogs.com/sunshine-1/p/8990044.html https://www.cnblogs.com/kismetv/p/7228274.html ...

  5. asp.net MVC中的@model与Model

    asp.net MVC中的@model与Model https://blog.csdn.net/ydm19891101/article/details/44301201 在MVC的实际使用中,我们经常 ...

  6. Qt 学习之路 2(73):Qt 线程相关类

    Home / Qt 学习之路 2 / Qt 学习之路 2(73):Qt 线程相关类 Qt 学习之路 2(73):Qt 线程相关类  豆子  2013年11月26日  Qt 学习之路 2  7条评论 希 ...

  7. 50行代码实现python计算器主要功能

    实现功能:计算带有括号和四则运算的式子   3*( 4+ 50 )-(( 100 + 40 )*5/2- 3*2* 2/4+9)*((( 3 + 4)-4)-4) 基本思路:使用正则表达式提取出每一层 ...

  8. pip不是内部或外部命令也不是可运行的程序或批处理文件的问题

    当我用windows电脑 pip install missingno 时 它居然会报pip不是内部或外部命令也不是可运行的程序或批处理文件的问题! 解决方法: 1)找到 pip.exe 所在位置,一般 ...

  9. 更改npm默认路径

    Windows下的Nodejs npm路径是appdata,如果你想通过npm在自己指定的路径下去搭建环境,那么就要去nodejs的安装目录中找到node_modules\npm\npmrc文件,修改 ...

  10. BZOJ - 2440 容斥定理

    组合枚举n/i/i,贡献为miu倍 /*H E A D*/ int mu[maxn],prime[maxn],cnt; bool isprime[maxn]; void sai(int n){ mu[ ...