我正在编写一个测试代码,它使用'request.js'和'async.js'从node.js上的Web API收集结果。
这是我的示例代码;
var request = require('request');
var async = require('async');
var addresses = [
"Tokyo",
"Moscow",
"Bagdhad",
"Mountain View",
"New York",
];
function accessUrl( address, callback ) {
options ={
headers: {'user-agent': 'Mozilla/5.0'},
url: 'http://api.openweathermap.org/data/2.5/weather?q=' + address,
json: true
};
request.get(options, function(err, response, body_json) {
if( !err && response.statusCode === 200 ){
return callback(address, body_json);
}
else{
console.log('error');
}
});
}
function showContent( address, body_json ) {
console.log( "%s : %s, %s (C)", address, body_json['weather'][0]['main'],
Math.round(body_json['main']['temp']-273.15));
return [ address, body_json['weather'][0]['main'],
Math.round(body_json['main']['temp']-273.15)];
}
var result = [];
async.map( addresses, function( item, callback ) {
result.push (accessUrl( item, showContent ));
}, function(err) {
});
console.log(result);
然而,结果是;
~$ node asyncsample1.js
[ undefined, undefined, undefined, undefined, undefined ]
Tokyo : Clear, 23 (C)
Mountain View : Mist, 10 (C)
Bagdhad : Clear, 10 (C)
New York : Clear, 22 (C)
Moscow : Clouds, 4 (C)
回调函数showContent()中的console.log()显示正确的结果,但收集的结果都是“未定义的”。
如何在var result []中获得结果?
答案 0 :(得分:4)
好的,让我向您介绍async
的{{1}}函数。这是你修改过的程序。
concat
<强>输出强>
var request = require('request');
var async = require('async');
var addresses = [
"Tokyo",
"Moscow",
"Bagdhad",
"Mountain View",
"New York",
];
function accessUrl( address, callback ) {
options ={
headers: {'user-agent': 'Mozilla/5.0'},
url: 'http://api.openweathermap.org/data/2.5/weather?q=' + address,
json: true
};
request.get(options, function(err, response, body_json) {
if( !err && response.statusCode === 200 ){
return callback(null, [[ address, body_json['weather'][0]['main'],
Math.round(body_json['main']['temp']-273.15)]]);
}
else{
return callback(err);
}
});
}
async.concat (addresses, accessUrl, function(err, result) {
if (err) {
console.error(err);
} else {
console.log(result);
}
});
您不必自己同步结果。 [ [ 'Mountain View', 'Haze', 17 ],
[ 'Bagdhad', 'Clear', 18 ],
[ 'New York', 'Clear', 26 ],
[ 'Tokyo', 'Clouds', 22 ],
[ 'Moscow', 'Clouds', 3 ] ]
为你做到了。
如果您有兴趣了解async的concat如何工作,请尝试使用
答案 1 :(得分:3)
您在此处将undefined推送到结果,因为accessUrl是异步的。它返回undefined。在执行accessUrl回调之前,您没有任何结果 - 但是到那时,即使它返回结果,也已经推送了undefined并且结果无处可去。
// wrong
var result = [];
async.map( addresses, function( item, callback ) {
result.push (accessUrl( item, showContent ));
}, function(err) {
});
任何依赖于异步函数结果的逻辑都必须进入该函数的回调。此外,async
为您处理输出数组,您只需将(err, result
传递给迭代器。
//corrected
async.map( addresses
, function( item, callback ){
accessUrl( item, function(address, body_json){
result = showContent(address, body_json);
// tell async.map there was no error and this is the mapped result
callback(null, result);
});
}
, function(err, results) {
console.log(results)
});
如果我是你,我会做一些调整。首先处理存在请求错误的情况。其次,我喜欢使用done
作为异步中回调的名称,因为我经常发现我在另一个异步函数中使用了异步,而且我通常有一个名为callback
的现有变量已经是回调父函数。所以我会这样做:
//improved
function iterator(item, done){
accessUrl( item, function(err, address, body_json){
// you will have to tweak accessUrl to callback with three parameters instead of two
if(err){ return done(err) };
// the `return` is necessary, otherwise latter lines will still execute
result = showContent(address, body_json);
// tell async.map there was no error and this is the mapped result
done(null, result);
});
};
async.map( addresses
, iterator
, function(err, results) {
if(err){ console.log(err) };
console.log(results)'
});
另一种方法,您可以在其中创建结果数组并逐个添加结果。这更接近你原来的想法,但由于async.map
自动构建结果数组,因此将此策略与async.map一起使用是没有意义的。
//alternative
function printWeather(callback){
var results = [];
async.forEachSeries(addresses
, function(item, done){
accessUrl( item, function(err, address, body_json){
if(err){ return done(err) };
result = showContent(address, body_json);
results.push(result);
done(null);
});
}
, function(err) {
if(err){ console.log(err) };
console.log(results);
//callback(err, results);
});
};