如何让动态插入的javascript脚本代码跑起来。


Posted in Javascript onJanuary 09, 2007

首先,声明方法很多种,直接间接的方法都有,只罗列一般情况下的两种模式:
假设我们要装入的代码是a.js:
var foo=function(){
document.write("I am a.js content foo() function by never-online");
};

一。直接插入src,这种方法简单而直接,但有局限性,
1)
<script>
var x=document.createElement("SCRIPT");
x.src="a.js"; x.defer=true;
document.getElementsByTagName("HEAD")[0].appendChild(x);
foo();
</script>

在如上的代码放上head标签内,执行时大多数情况下是会出错,信息为:错误:缺少对象
这是由于动态创建对象script时,则于a.js还没有完全载入而导致的。执行下面的代码,你就可以发现原因了。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>never-online dynamic code test page</title>
</head>
<body>
<pre>

readyState的含义
 - uninitialized : 脚本对象刚被创建,脚本代码未载入;
 - loading : 脚本代码载入中;
 - loaded : 脚本代码完成读入,但尚未开始解释执行;
 - interactive : 解释执行过程中;
 - complete : 脚本已经执行完成。

</pre>
<div id="viewer"></div>
<script type="text/javascript">

window.onerror=function(msg,url,line){
  document.getElementById("viewer").innerHTML+='<p style="color:red">错误:'+msg+'line:'+line+'</p>';
  return true;
}

function bar(u) {
  var x=document.createElement("SCRIPT");
  x.src=u;
  x.defer=true;
  document.getElementsByTagName("HEAD")[0].appendChild(x);
}
bar("a.js");

(function getReadyState(){
  var e=document.getElementById("viewer")
  var x=true;
  var a = document.getElementsByTagName("SCRIPT");
  for (var i=0; i<a.length; i++) {
    if (a[i].readyState=='complete' && x!=false) x=true; else x=false
    e.innerHTML+=(a[i].src?a[i].src+':':'noname:')+a[i].readyState+"<br />";
  }
  e.innerHTML+="<hr/>";
  if (x) window.clearTimeout(window.timer); else
  window.timer=window.setTimeout('getReadyState()',1000);
}());

foo();

</script>
<script type="text/javascript">
//<![CDATA[
foo();
//]]>
</script>
</body>
</html>
初始值为:
a.js:loading
noname:interactive
我们可以知道,a.js依然在loading状态,在执行foo()当然是错误的。但下一个script标签执行中,a.js的readyState是complete了,所以可以执行foo()的函数。由此,我推荐你可以简单的这样运用动态用生成script标签方法来添加js的url。
解决方法如下
1)用window.setTimeout方法来执行,估计a.js已经载入完毕,才执行a.js里的函数。这个方法仍然不保险
<script>
var x=document.createElement("SCRIPT");
x.src="a.js"; x.defer=true;
document.getElementsByTagName("HEAD")[0].appendChild(x);
window.setTimeout('foo()',1000);
</script>
2)多加一个script标签放置要执行的代码
<script>
var x=document.createElement("SCRIPT");
x.src="a.js"; x.defer=true;
document.getElementsByTagName("HEAD")[0].appendChild(x);
</script>
<script>
//多一个script标签来放置
//这里a.js的readyState已经为complete了。
foo();
</script>

二、用XMLHttpRequest和window.execScript动态的执行a.js,这个方法的优点比较明显,但效率可能有所下降,没有测试,有兴趣的朋友可以自己测试一下速度。
代码如下:
<script language="javascript">
function bar(u) {
  var x=window.ActiveXObject?new ActiveXObject("MSXML2.XMLHTTP"):new XMLHttpRequest();
  x.open("GET",u,false);
  x.send(null);
  s=x.responseText;
  try {window.execScript(s)}catch(ex){window.eval(s)};//Mozilla下window.eval大致与IE的window.execScript方法功能相同
}
bar("a.js");
foo();
</script>
但这个方法仍有缺点,也就是a.js脚本中的代码有中文的情况,如何处理?那就要经常解码了,而解码恰恰是js的软肋,如果运用vbs来解码,那么兼容也就没有了。要看自己具体的应用了,我在neverModules里加载js包时用的就是window.execScript方法来解析代码,这样更可以配合js namespace的应用

顺便再加上解码

 <script type="text/javascript">
 //<![CDATA[
  function bar(u) {
    var x=window.ActiveXObject?new ActiveXObject("MSXML2.XMLHTTP"):new XMLHttpRequest();
    x.open("GET",u,false);
    x.send(null);
    s=parseScript(x.responseText);
    try {window.execScript(s)}catch(ex){window.eval(s)};
  }
  function parseScript(jscode) {
 // --- toCurrentCharset(), by aimingoo 解码
 window.execScript(''+
 'Function Asc2Unicode(n) \n'+
 ' Asc2Unicode = Chr(n) \n'+
 'End Function \n'+

 'Function SafeArray2Str(body) \n'+
 ' SafeArray2Str = CStr(body)\n'+
 'End Function','VBScript');

 var r1 = /%u(..)(..)/g, r2 = /%([8,9,A-F].)%(..)/g;
 var toUnicode = function($0, $1, $2) {return Asc2Unicode(parseInt($1+$2, 16))}
 toCurrentCharset = function(body) {
 return unescape(escape(SafeArray2Str(body)).replace(r1, "%$2%$1").replace(r2, toUnicode));
 }; jscode=toCurrentCharset(jscode); 
    window.execScript(jscode, 'JavaScript'); //IE有效,vbs解码
    return jscode;
 }

  bar('a.js');

  foo();
 //]]>
 </script>

不过大多数的情况下,第二种方法处理起来应该没有问题,如果要很严格的执行的话,第一种方法还是有改进的代码的,比如加载a.js的内容,把本身的脚本再次解析再执行,但复杂度就提高了,所以要有一个非常完美的解决方案,还需要更进一步来讨论。
我就不写这么多了,仅仅为一个提醒,还有一个抛砖引玉的作用。

Javascript 相关文章推荐
jQuery TextBox自动完成条
Jul 22 Javascript
javascript 进阶篇3 Ajax 、JSON、 Prototype介绍
Mar 14 Javascript
js中使用replace方法完成某个字符的转换
Aug 20 Javascript
jQuery 获取多选框的值及多选框中文的函数
May 16 Javascript
Bootstrap Modal遮罩弹出层(完整版)
Nov 21 Javascript
提升页面加载速度的插件InstantClick
Sep 12 Javascript
微信小程序中使用自定义图标(阿里icon)的方法
Aug 20 Javascript
JQuery搜索框自动补全(模糊匹配)功能实现示例
Jan 08 jQuery
vue中keep-alive,include的缓存问题
Nov 26 Javascript
IDEA配置jQuery, $符号不再显示黄色波浪线的问题
Oct 09 jQuery
token 机制和实现方式
Dec 15 Javascript
vue @click.native 绑定原生点击事件
Apr 22 Vue.js
JS效率个人经验谈(8-15更新),加入range技巧
Jan 09 #Javascript
你所要知道JS(DHTML)中的一些技巧
Jan 09 #Javascript
sina的lightbox效果。
Jan 09 #Javascript
JS中简单的实现像C#中using功能(有源码下载)
Jan 09 #Javascript
在修改准备发的批量美化select+可修改select时,在非IE下发现了几个问题
Jan 09 #Javascript
兼容Mozilla必须知道的知识。
Jan 09 #Javascript
尽可能写&quot;友好&quot;的&quot;Javascript&quot;代码
Jan 09 #Javascript
You might like
在线短消息收发的程序,不用数据库
2006/10/09 PHP
php使用array_rand()函数从数组中随机选择一个或多个元素
2014/04/28 PHP
php实现网页缓存的工具类分享
2015/07/14 PHP
PHP添加PNG图片背景透明水印操作类定义与用法示例
2019/03/12 PHP
网页中实现浏览器的最大,最小化和关闭按钮
2007/03/12 Javascript
JS截取字符串常用方法详细整理
2013/10/28 Javascript
js 左右悬浮对联广告代码示例
2014/12/12 Javascript
浅谈JavaScript超时调用和间歇调用
2015/08/30 Javascript
如何实现JavaScript动态加载CSS和JS文件
2020/12/28 Javascript
基于jquery编写分页插件
2016/03/07 Javascript
JavaScript 动态三角函数实例详解
2017/01/08 Javascript
vue使用watch 观察路由变化,重新获取内容
2017/03/08 Javascript
说说AngularJS中的$parse和$eval的用法
2017/09/14 Javascript
原生JS+CSS实现炫酷重力模拟弹跳系统的登录页面
2017/11/01 Javascript
Angular 容器部署的方法
2018/04/17 Javascript
vue如何判断dom的class
2018/04/26 Javascript
使用node.js实现微信小程序实时聊天功能
2018/08/13 Javascript
NodeJs操作MongoDB教程之分页功能以及常见问题
2019/04/09 NodeJs
JS+css3实现幻灯片轮播图
2020/08/14 Javascript
[03:07]DOTA2英雄基础教程 冰霜诅咒极寒幽魂
2013/12/06 DOTA
Python字符串详细介绍
2015/05/09 Python
Python冒泡排序注意要点实例详解
2016/09/09 Python
Tensorflow:转置函数 transpose的使用详解
2020/02/11 Python
Python yield的用法实例分析
2020/03/06 Python
Python判断三段线能否构成三角形的代码
2020/04/12 Python
keras 自定义loss model.add_loss的使用详解
2020/06/22 Python
基于django2.2连oracle11g解决版本冲突的问题
2020/07/02 Python
Win10下配置tensorflow-gpu的详细教程(无VS2015/2017)
2020/07/14 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
2021/01/15 Python
美国优质宠物用品购买网站:Muttropolis
2020/02/17 全球购物
什么是Oracle的后台进程background processes?都有哪些后台进程?
2012/04/26 面试题
青年创业培训欢迎词
2014/01/10 职场文书
涉外离婚协议书怎么写
2014/11/20 职场文书
创卫工作总结2015
2015/04/22 职场文书
MongoDB orm框架的注意事项及简单使用
2021/06/20 MongoDB
Windows server 2016服务器基本设置
2022/08/14 Servers