我遇到了似乎是Node JS初学者和异步请求的传统问题。
我有一个未知数量的URL由用户生成,随后存储在我的Node JS服务器上的数组中。 Node JS服务器必须遍历这些URL,依次向每个URL发出请求。它必须按顺序执行,并且必须等待每个响应才能转到下一个URL(当发出新请求时)。最终结果应该是所有响应(恰好是JSON)的有序集合,很好地存储在一起作为JSON对象,然后可以在准备好时将其发送回客户端。
我想我应该使用async
NodeJS库,我已经使用needle
来发出请求。
URLs = ["http://a", "http://s", "http://d"];
async.eachSeries(URLs, function (URL, callback) { ..... });
我不清楚如何使用async来确保Needle请求已完成,并在转移到下一个URL请求之前相应地存储该响应。以下是我的Needle请求的示例。
needle.get(URL, options, function(error, response, body){ ... });
欢迎部分或完整解决整个问题。
答案 0 :(得分:10)
有了承诺,你可以用:
var Promise = require("bluebird");
var get = Promise.promisify(needle.get, needle);
var URLs = ["http://a", "http://s", "http://d"];
var current = Promise.fulfilled();
Promise.map(URLs, function (URL) {
current = current.then(function () {
return get(URL);
});
return current;
}).map(function(responseAndBody){
return JSON.parse(responseAndBody[1]);
}).then(function (results) {
console.log(results);
}).catch(function (e) {
console.error(e);
});
作为奖励,当网站包含无效的json或响应错误消息/空体时,您的服务器不会崩溃。手写时,您需要手动尝试捕获,但承诺会处理catch()
中的两种错误。由于网址由用户提供,如果您不向非承诺代码添加手动try-catch,他们可以轻松地对您的服务器执行操作。
答案 1 :(得分:4)
这里有两个示例,一个用async.eachSeries
逐个保存结果,另一个用async.mapSeries
收集所有结果,然后一次性保存所有结果
URLs = ["http://a", "http://s", "http://d"];
function iterator1(URL, done){
var options = {};
needle.get(URL, options, function(error, response, body){
if(error){ return done(error) };
processAndSaveInDB(body, function(err){
if(err){ return done(err) };
done(null);
});
});
};
async.eachSeries(URLs
, iterator1
, function (err){
// global callback for async.eachSeries
if(err){
console.log(err)
} else {
console.log('All Needle requests successful and saved');
}
});
// Here is a similar technique using async.map, it may be more suitable
function iterator2(URL, done){
var options = {};
needle.get(URL, options, function(error, response, body){
if(error){ return done(error) };
done(null, body);
});
};
async.mapSeries(URLs
, iterator2
, function (err, results){
// global callback for async.mapSeries
if(err){
console.log(err)
} else {
console.log('All Needle requests successful');
// results is a 1 to 1 mapping in order of URLs > needle.body
processAndSaveAllInDB(results, function(err){
if(err){ return done(err) };
console.log('All Needle requests saved');
done(null);
});
}
});
我不清楚如何使用async来确保Needle请求已完成,并在转移到下一个URL请求之前相应地存储该响应。
异步函数的series
变体处理这个问题;您只需确保在准备好继续之前不要调用迭代器函数的done
回调。实际上,这意味着将done
的呼叫置于最里面的回调中(例如你的针回调)