`

我对Javascript渲染加载以及解释调用顺序的一点理解

阅读更多
      原本在项目中的需求是这样的,向服务器提交一个Ajax请求后,在服务器的FTL中生成动态的数据后返回,同时在FTL模板文件中夹杂了一些JS脚本以及XX方法定义,渲染返回后直接作为文本添加到客户端页面DIV的innerHTML。先暂且不论这种方式的优劣,就这个需求看,大家应该理解我的用意是在页面中去调用Ajax返回生成的js代码。按我原来的想法,只要在回调函数返回后将我将要调用JS代码加载到当面页面中的某个DIV的innerHTML,包含XX方法,然后就可以顺利调用XX方法。但是事实上,会出现XX方法 is not defined的问题。我个人将这个问题定义为由于对浏览器对JS的渲染加载以及解释调用顺序不理解造成的设计错误。鉴于项目中的代码过于庞大,对于这个问题,我写了个测试页面来进行分析,新建一个test.htm:
<script>
	function a(){
		sadasd
		alert("a");
	}
	function c(){
		document.getElementById("test1").innerHTML="<script>function z(){alert(\"z\");}<\/script>";
		z();
	
	}
	function d(){
		document.getElementById("test2").innerHTML="";
		b();
	
	}
</script>
<input type="button" value="test_a" onclick="a();">
<input type="button" value="test_b" onclick="b();">
<input type="button" value="test_c" onclick="c();">
<input type="button" value="test_d" onclick="d();">
<div id="test1"></div>
<div id="test2">
<script>
	function b(){
		alert("b");
	}
</script>
</div>

       首先,你用浏览器打开该页面时,应该不会有任何错误。这说明浏览器加载页面对JS进行渲染解释时并没有去解释方法内部的实现,因为方法a()中我写了一行没有语法规则的字符串,如果刚才解析了必会报错。
      然后你点击按钮test_b,你会发现b()方法顺利调用了,没有出现问题。
      接着,你点击按钮test_a,发现并没有alert(a),而是报了'sadasd' 未定义的错误。可见js方法中的内容是在方法被调用时去解析的。
      到此,我解释下方法c(),d()的设计用意。
      方法c(),我是模拟了本文开头提到的ajax回调方法中向页面div的innerHTML添加js方法定义这种场景。通过添加按钮test_c,触发方法c(),在方法c()中向id为“test1”的div的innerHTML添加了方法z()的定义,代码仅仅是非常简单的alert("z")。然后试图调用z(),这也正是我当时遇到的错误。
      方法d()是对c()的结论一个再次论证,如果我在d()中清除了div“test2”中的innerHTML,即删除了方法b()的定义,那我还能调用b()嘛?
     
      思考一分钟,预测下你的结果?
    
      然后你义无反顾的点击按钮test_c,发现z is not defined的错误。
      如果此时你通过firebug去查看“test1”div,你可以看到存在:
        <script>function z(){alert("z");}</script>

     但是为什么会报z is not defined呢?
     接着你疑惑着去点击test_d,结果b调用又成功了....alert了b.

     我的理解是这样的(纯属个人通过实验的结论):
     1.浏览器在第一次加载页面后将所有<script>标签内的js放入浏览器中属于js的上下文内存栈,然后解析并执行所有<script>标签内的js全局脚本。(这也就是为什么在后面通过事件往页面innerHTML添加的js方法被认为是is not defined的原因,而我们删除的b()却还可以调用)
     2.在事件触发等原因造成方法被调用时,首先去上下文栈里查找该方法定义,找到的解释并执行该方法(所以a()在此时报错了),否则报XX is not defined的错误。

      暂时做个实验记录,有时间再去看看具体浏览器对JS引擎的相关实现。
    



分享到:
评论
3 楼 shhbobby 2011-02-15  
我的理解跟博主的差不多
在页面加载的时候,所有的javascript都加载并且处于激活状态
当 ajax返回js之后 不知道有没有办法让浏览器再把返回来的js也激活就好了
2 楼 emsn 2010-06-30  
eason007 写道
inner对js是没有用的,要用eval。

删除inner同样对js无效


这话有点片面,比如阁下对“inner对js是没有用的”的具体指哪种无效,比如我如下:
<script>
	function e(){
		document.getElementById("test").innerHTML="<input type=\"button\" onclick=\"javascript:function y(){alert(123);} y();\"/>";	
	}
</script>
<input type="button" value="test_e" onclick="e();">
<div id="test"></div>
<script>

中对于y()的定义和执行也是没问题的,这也是innerHTML对js的一种“有效”。eval的话是动态的去解释执行js字符串,它跨越了浏览器对于js解释执行顺序的界限,肯定是可以的。我讨论的是浏览器对于js的加载以及解释的顺序,我还是比较希望有老鸟这方面能给予一些详细的讲解,来验证我的实验的某些细节甚至是设计思路是否正确。
1 楼 eason007 2010-06-30  
inner对js是没有用的,要用eval。

删除inner同样对js无效

相关推荐

Global site tag (gtag.js) - Google Analytics