具有异步请求的 NodeJS

NodeJS with Async requests

本文关键字:NodeJS 请求 异步      更新时间:2023-09-26

我遇到了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) { ..... });

我不清楚如何使用异步来确保 Needle 请求已完成,并在移动到下一个 URL 请求之前相应地存储该响应。下面是我的针头请求示例。

 needle.get(URL, options, function(error, response, body){ ... });

欢迎部分或全部解决整个问题。

有了承诺,你可以用:

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()中的两种错误。由于 url 是由用户提供的,因此如果您不将手动 try-catch 添加到非承诺代码中,它们可以轻松地 DoS 您的服务器。

这里有两个示例,一个是使用 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);
    });
  }
});

我不清楚如何使用异步来确保 Needle 请求已完成,并在移动到下一个 URL 请求之前相应地存储该响应。

异步函数的series变体可以解决这个问题;您只需确保在准备好继续之前不要调用迭代器函数的done回调。实际上,这意味着将调用done放在最内在的回调中(例如,您的 Needle 回调)