如何让动态插入的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 相关文章推荐
js 提交和设置表单的值
Dec 19 Javascript
javascript 解析后的xml对象的读取方法细解
Jul 25 Javascript
Js 时间间隔计算的函数(间隔天数)
Nov 15 Javascript
JavaScript 数组详解
Oct 10 Javascript
js使用递归解析xml
Dec 12 Javascript
jQuery实现的精美平滑二级下拉菜单效果代码
Mar 28 Javascript
node-http-proxy修改响应结果实例代码
Jun 06 Javascript
vue通过路由实现页面刷新的方法
Jan 25 Javascript
Javascript通过控制类名更改样式
May 24 Javascript
JavaScript 实现HTML DOM增删改查操作的常见方法详解
Jan 04 Javascript
JS forEach跳出循环2种实现方法
Jun 24 Javascript
Element InputNumber 计数器的实现示例
Aug 03 Javascript
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
php生成mysql的数据字典
2016/07/07 PHP
LBS blog sql注射漏洞[All version]-官方已有补丁
2007/08/26 Javascript
jQuery源码分析-02正则表达式 RegExp 常用正则表达式
2011/11/14 Javascript
js中点击空白区域时文本框与隐藏层的显示与影藏问题
2013/08/26 Javascript
js中浮点型运算BUG的解决方法说明
2014/01/06 Javascript
$.each与$().each的区别示例介绍
2014/03/20 Javascript
详解JavaScript中数组的相关知识
2015/07/29 Javascript
JS+CSS实现简易实用的滑动门菜单效果
2015/09/18 Javascript
使用Javascript写的2048小游戏
2015/11/25 Javascript
JavaScript通过代码调用Flash显示的方法
2016/02/02 Javascript
Vue.js结合Ueditor富文本编辑器的实例代码
2017/07/11 Javascript
微信小程序之电影影评小程序制作代码
2017/08/03 Javascript
微信小程序列表中item左滑删除功能
2018/11/07 Javascript
如何在JavaScript中优雅的提取循环内数据详解
2019/03/04 Javascript
详解Node.js一行命令上传本地文件到服务器
2019/04/22 Javascript
解决小程序无法触发SESSION问题
2020/02/03 Javascript
详解vue中在父组件点击按钮触发子组件的事件
2020/11/13 Javascript
[01:03:18]DOTA2-DPC中国联赛 正赛 RNG vs Dynasty BO3 第一场 1月29日
2021/03/11 DOTA
python 获取et和excel的版本号
2009/04/09 Python
python使用ctypes模块调用windowsapi获取系统版本示例
2014/04/17 Python
Python二分法搜索算法实例分析
2015/05/11 Python
深入理解python多进程编程
2016/06/12 Python
Python查找两个有序列表中位数的方法【基于归并算法】
2018/04/20 Python
Python数据结构dict常用操作代码实例
2020/03/12 Python
如何利用Python动态模拟太阳系运转
2020/09/04 Python
Html5应用程序缓存(Cache manifest)
2018/06/04 HTML / CSS
跨域修改iframe页面内容详解
2019/10/31 HTML / CSS
Marc Jacobs彩妆官网:Marc Jacobs Beauty
2017/07/03 全球购物
美国著名的家居用品购物网站:Bed Bath & Beyond
2018/01/05 全球购物
广州某公司软件工程师面试题
2014/12/22 面试题
《东方明珠》教学反思
2014/04/20 职场文书
2014年实习班主任工作总结
2014/11/08 职场文书
党员个人年度总结
2015/02/14 职场文书
教师工作能力自我评价
2015/03/04 职场文书
学习经验交流会演讲稿
2015/11/02 职场文书
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL