首页 > 代码库 > 移除script标签引起的兼容性问题

移除script标签引起的兼容性问题

一、应用场景:

有时候我们需要动态创建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 = http://www.mamicode.com/this.getScriptPath(options.src);"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.srchttp://www.mamicode.com/= "";            objScript.parentNode.removeChild(objScript);            objScript = null;        }    } catch (e) {    }    if (objScript != null) {        if (dataHref.indexOf("?") == -1)            dataHref += "?";        dataHref += "&" + Math.random();        objScript.src = http://www.mamicode.com/dataHref;"script");        if (scriptId) {            dataScript.id = scriptId;        }        if (charset) {            dataScript.charset = charset;        }        try {            if (dataHref.indexOf("?") == -1) {                dataHref = http://www.mamicode.com/M139.Text.Url.makeUrl(dataHref, {"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标签引起的兼容性问题