Javascript中的线程以及获取动态Dom元素的问题--thread/appendChild/setTimeout

来源:互联网 发布:html页面嵌入php 编辑:程序博客网 时间:2024/05/16 17:30
前一段时间做一个东西,出现几次“缺少对象”的错误,总结了一下,都和javascript的执行顺序有关,但是搜索了一下,javascript中好像没有线程的概念,只存在执行的先后顺序(某一个部分完成以后,才开始另外的部分),这种情况一般在用setTiemout或者XMLHttpRequest(Asynchronous)时出现。

一、首先是异步XMLHttpRequest(async)的回调函数(callback)的执行顺序,一开始我写了类似下面的代码,但是变量b一直是空的(异步请求正常):

var a = "";
... ...
request.onreadystatechange = function(data){
if(request.readyState == 4 && request.status == 200){
    a = data;
}
}
request.open ('GET', path, true);//如果设置为false,则不是异步,代码会按顺序执行
var b = a.length;

最后把对数据的操作放到回调函数里面,解决问题,改成下面这样:
request.onreadystatechange = function(data){
if(request.readyState == 4 && request.status == 200){
    a = data;
    var b = a.length;
}
}

二、其次是在javascript获取动态生成的Dom元素的问题
,用javascript来生成界面,然后对生成的元素进行操作,老是报错“缺少对象”。简化代码如下:

window.onload = function(){
var body = document.getElementsByTagName("body")[0];
var elmt = document.createElement( "p" );
elmt.id = "hello";
var txt = document.createTextNode( "hello" );
elmt.appendChild(txt);
var did = document.getElementById("hello");
alert(did.id);
body.appendChild(elmt);
}

取不到用createElement创建的对象,可是,这个对象在调用前明明已经被创建了啊。后来发现,对这个对象进行操作之前,并没有把它添加到整个文档中去,于是调整了一下代码的顺序:

body.appendChild(elmt);
var did = document.getElementById("hello");
alert(did.id);

运行正常了。可是又有新问题,当我把它放到一个稍微复杂的环境中去,只能在最后的时候一次把所有的Dom元素添加到文档中,也就是appendChild(elmt)不可能放到getElementById(elmtId)前面,于是又一番google/baidu,发现这是一个很普遍、基础的问题,同时也发现setTimeout的奇妙用途,让javascript代码按非顺序执行:

setTimeout(
function(){
   var did = document.getElementById("hello");
   alert(did.id);
},0);
body.appendChild(elmt);

这样的话,即使setTimeout设置的延迟为0,它里面的函数也会在所有代码执行完以后,才开始执行,于是问题也就解决了。

参考:
Realazy: 认识延迟时间为 0 的 setTimeout
Javascriptkata: Ajax, javascript and threads : the final truth
Fitzblog: Nine Javascript Gotchas