一、应用场景:

有时候我们需要动态创建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. Java面向对象之多态(成员访问特点) 入门实例

    一.基础概念 多态的调用方式在子父类中的特殊体现. 1.访问成员变量特点: 当子父类中出现同名成员变量时. 多态调用时,编译和运行都参考引用型变量所属的类中的成员变量. 即编译和运行看等号的左边. 2 ...

  2. 在libuv中使用openssl建立ssl连接

    在libuv中使用openssl建立ssl连接 @(blogs) 使用openssl进行加密通信时,通常是先建立socket连接,然后使用SSL_XXX系列函数在普通socket之上建立安全连接,然后 ...

  3. Python之路Python全局变量与局部变量、函数多层嵌套、函数递归

    Python之路Python全局变量与局部变量.函数多层嵌套.函数递归 一.局部变量与全局变量 1.在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量.全局变量作用域是整个程序,局 ...

  4. Python中实现简单的插件框架

    在系统设计中,经常我们希望设计一套插件机制,在不修改程序主体情况下,动态去加载附能. 我设想的插件系统: 1.通过类来实现 2.自动查找和导入 我们假设需要实现一个简单的插件系统,插件可以接收一个参数 ...

  5. postgresql编译安装与调试(一)

    因为最近组里的项目和postgresql有关,并且需要查看和调试源码,所以专门学习了一下如何安装和调试postgresql,此博文用来记录自己的安装和调试过程.安装环境是CentOS6(CentOS7 ...

  6. Liunux疑问

    Liunux疑问 其中的各种软件的安装有模糊的点,待解决 待解决 待解决 待解决 ... ...

  7. ThinkCMF Volist标签

    volist标签通常用于查询数据集(select方法)的结果输出,通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出. 在控制器中首先对模版赋值: $User = ...

  8. 按钮重复点击问题 UIbutton

    .h #import <UIKit/UIKit.h> #import <objc/runtime.h> @interface UIControl (XY) @property ...

  9. Jmeter拓展插件可查看和lr一样的图形结果

    利用插件可通过图形直观查看CPU.Memory等的运行情况 1. JmeterPlugins.jar插件下载地址:http://jmeter-plugins.org/downloads/all 下载并 ...

  10. chrome 相关设置.

    1. 使用chrome 添加道桌面的快捷方式,自动打开两个 tab 解决方法: chrome://apps/ 右击 你的应用图标..勾选在新窗口打开.