小弟希望通过调用http的get服务,把返回的response中的某一个link赋值给一个变量然后给后续代码使用。问题是在回调中赋值的结果,在主线程中无法获取。
var url_path;
http.get(options,function(res){
res.on("data",function(chunk){
var data_json = JSON.parse(chunk.toString());
var links = data_json.links;
for (var i = 0;i<links.length;i++){
if (links[i].rel == "down"){
url_path = links[i].href;
console.log(1)
}
}
});
});
};
var second = new Date().getSeconds();
while (new Date().getSeconds() < second+6);
console.log(url_path);
console.log(2)
上面的代码就是希望把某一个rel为down的连接赋值为url_path, 这个http的操作很快的。我在主线程里面尝试了sleep了6秒钟,但是打印出来的url_path还是为undefined。而且奇怪的事情是,我代码中的打印数字的次序也不是我期望的,竟然是先打印2,再打印1,这个是为什么呢。求解啊,求高人帮忙啊
@markshao 可以这样理解异步:某天你家来了个客人,你想弄杯茶给客人喝,需要做这几个事情:烧水、洗茶杯、泡茶。
阻塞型的做法是:先烧水,一直盯着直到水开了,然后去洗茶杯,然后再泡茶;
如果是异步的话,则是:烧水,反正水一时半会还没开,顺便把茶杯给洗了,如果还有时间的话,跟客人聊聊天,等水烧开了再泡茶。
你的代码中的这部分就相当于一直盯着那个水壶,等水开了想要泡茶,可是茶杯还没洗好,于是杯具了:
var second = new Date().getSeconds(); while (new Date().getSeconds() < second+6); console.log(url_path); console.log(2)
你上面的代码可写成这样:
var url_path;
// 这个是回调函数,等获取到url_path后要执行的程序
var callback = function () {
console.log(url_path);
console.log(2)
};
http.get(options,function(res){
res.on("data",function(chunk){
var data_json = JSON.parse(chunk.toString());
var links = data_json.links;
for (var i = 0;i<links.length;i++){
if (links[i].rel == "down"){
url_path = links[i].href;
console.log(1);
// 执行回调函数
callback();
}
}
});
});
@leizongmin 说的有理,不过LZ的问题还是不是出在这里!!
res.on(“data”)是每次有新数据来的时候调用,这样http get获取的不完整数据每次来的时候都执行了同样代码,最后LZ认为获取完整的数据其实是不完整的!
http.get()的回调中这么写:
var data = "";
res.on("data", function(chunk){
data += chunck;
});
res.on("end", function(){
var data_json = JSON.parse(data.toString());
//下面自己处理吧
});
我根据你的提示下了一个demo测试了一下,
var p = 1;
http.get(options,function(res){ console.log(res.statusCode); res.on("data",function(chunk){ console.log(3); }); res.on("end",function(){ console.log(4); p = 4; }); });
结果还是不对的,
"C:\Program Files\nodejs\node.exe" httptest.js
1 200 3 3 3 3 4
我现在怀疑是我的while循环导致主线程被block了,由于nodejs是单线程的,所以可能那个时候的回调也没有执行。
所以我可以理解为,回调函数其实是在nodejs的主线程里面运行的,只有IO是在单独的线程中运行的。我这样的代码结构,就导致了,回调函数的执行顺序永远在while语句的后面。
可见nodejs不太适合这样的写法。犹豫我是因为拿这个来做一个测试restful的测试框架,需要每次case执行之前去把一个变量赋值。虽然可以把case写道回调中,但是总是会导致代码的可读性变低。
看来nodejs的用途还是有限的。不过可以考虑某些地方用同步的IO来实现。这样业务的逻辑性就可以比较好的保留了。
你的理解是对的,就是这样,只有一个线程。其实每个异步的“任务”都会塞进一个task queue里,等待main thread pick it up。当前的函数 while(true)了,main thread已经阻塞,自然没有机会pick up task
http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-loops
@markshao 你这个执行结果没有诡异之处~
说你的主线程被while循环block了,可以这么理解,但是不恰当!
首先nodejs是单线程的,无所谓什么主线程
然后nodejs顺序执行,遇到IO操作就会交给回调处理,然后继续向下运行,你的while循环当然没有IO操作,因此肯定先执行了,又因为执行while循环的时候,nodejs是没有出现等待IO这样的空闲的,所以即使这个时候http get操作已经获取数据完毕,也是得不到处理的机会的,只有等到while循环结束!
看你的执行结果:
第一个1我不知道你是log的什么
第二个200是while循环执行完毕后,处理http get的回调时log的res.status(code),表示数据接收成功
接下的四个3是从接收的数据piping出来的过程,所以要在“data”事件里写data += chunk
piping完数据后,触发end事件,所以最后log的是4~
(有些地方可能我也表述不清,只是说下我的理解!)
@sunshine1988 lz说main thread的意思是main thread这个概念(在browser里就是ui thread)吧。而且nodejs其他的api的执行是否有起线程又不清楚。。。lz说main thread只是说相对于c++(.node 模块)代码来说,js的执行线程类似main thread吧。