Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/42.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 节点异步循环-如何使此代码按顺序运行?_Javascript_Node.js_Asynchronous - Fatal编程技术网

Javascript 节点异步循环-如何使此代码按顺序运行?

Javascript 节点异步循环-如何使此代码按顺序运行?,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,我知道有几个帖子是关于这一点的,但根据我发现的,这应该是正确的 我想在循环中发出http请求,并且我不希望循环在请求回调被触发之前进行迭代。我使用的异步库如下所示: const async = require("async"); const request = require("request"); let data = [ "Larry", "Curly", "Moe" ]; async.forEachOf(data, (result, idx, callback)

我知道有几个帖子是关于这一点的,但根据我发现的,这应该是正确的

我想在循环中发出http请求,并且我不希望循环在请求回调被触发之前进行迭代。我使用的异步库如下所示:

const async = require("async");
const request = require("request");

let data = [
    "Larry",
    "Curly",
    "Moe"
];

async.forEachOf(data, (result, idx, callback) => {
    console.log("Loop iterated", idx);
    let fullUri = "https://jsonplaceholder.typicode.com/posts";
    request({
        url: fullUri
    }, 
    (err, res, body) => {
        console.log("Request callback fired...");
        if (err || res.statusCode !== 200) return callback(err);
        console.log(result);
        callback();
    });
});
我看到的是:

Loop iterated 0
Loop iterated 1
Loop iterated 2
Request callback fired...
Curly
Request callback fired...
Larry
Request callback fired...
Moe
我需要看到的是:

Loop iterated 0
Request callback fired...
Curly
Loop iterated 1
Request callback fired...
Larry
Loop iterated 2
Request callback fired...
Moe
另外,如果有一种内置的方式来异步/等待做同样的事情?许诺而且可以删除异步库,这会更好

我已经看到了一些非常聪明的递归示例,但是当我将其用于更复杂的情况时,例如,每个循环都有多个请求调用,等等。我觉得这种方法很难遵循,而且可读性也不高。

您可以完全抛弃异步,而很容易地使用异步/等待

承诺您的请求并使用async/Wait 只要把请求变成承诺,你就可以等待

更好的方法是,只使用已经使用本机承诺包装的请求

系列示例 从那时起,通过async/await进行扣篮:

平行示例 现在,上述解决方案的问题是速度慢——请求连续运行。大多数情况下,这并不理想

如果下一个请求不需要上一个请求的结果,只需继续并执行Promise.all即可触发并行请求

const users = [1, 2, 3, 4]

const pendingPromises = []
for (const idUser of users) {
  // Here we won't `await` on *each and every* request.
  // We'll just prepare it and push it into an Array
  pendingPromises.push(rp('http://foo.com/users/' + idUser))
}

// Then we `await` on a a `Promise.all` of those requests
// which will fire all the prepared promises *simultaneously*, 
// and resolve when all have been completed
const results = await Promise.all(pendingPromises)
错误处理 async/await中的错误处理是由普通的try..catch块提供的,为了简洁起见,我省略了它。

您可以完全放弃async,很容易地选择async/await

承诺您的请求并使用async/Wait 只要把请求变成承诺,你就可以等待

更好的方法是,只使用已经使用本机承诺包装的请求

系列示例 从那时起,通过async/await进行扣篮:

平行示例 现在,上述解决方案的问题是速度慢——请求连续运行。大多数情况下,这并不理想

如果下一个请求不需要上一个请求的结果,只需继续并执行Promise.all即可触发并行请求

const users = [1, 2, 3, 4]

const pendingPromises = []
for (const idUser of users) {
  // Here we won't `await` on *each and every* request.
  // We'll just prepare it and push it into an Array
  pendingPromises.push(rp('http://foo.com/users/' + idUser))
}

// Then we `await` on a a `Promise.all` of those requests
// which will fire all the prepared promises *simultaneously*, 
// and resolve when all have been completed
const results = await Promise.all(pendingPromises)
错误处理
async/await中的错误处理由普通的try..catch块提供,为了简洁起见,我省略了它。

如果要处理数千个URL,最好定义一个批大小并递归调用process函数来处理一个批

最好限制活动连接的数量,您可以使用限制活动连接或在特定时间内每秒仅5次的连接

最后但并非最不重要;如果你使用诺言,你就要确保当一个诺言被拒绝时,不会失去所有的成功。您可以捕获被拒绝的请求并返回失败类型对象,这样它就可以使用此失败类型进行解析

代码如下所示:

const async = require("async");
//lib comes from: https://github.com/amsterdamharu/lib/blob/master/src/index.js
const lib = require("lib");
const request = require("request");

const Fail = function(reason){this.reason=reason;};
const isFail = o=>(o&&o.constructor)===Fail;
const requestAsPromise = fullUri =>
  new Promise(
    (resolve,reject)=>
      request({
        url: fullUri
      }, 
      (err, res, body) => {
        console.log("Request callback fired...");
        if (err || res.statusCode !== 200) reject(err);
        console.log("Success:",fullUri);
        resolve([res,body]);
      })
  )
const process = 
  handleBatchResult =>
  batchSize =>
  maxFunction =>
  urls =>
    Promise.all(
      urls.slice(0,batchSize)
      .map(
        url=>
          maxFunction(requestAsPromise)(url)
          .catch(err=>new Fail([err,url]))//catch reject and resolve with fail object
      )
    )
    .then(handleBatch)
    .catch(panic=>console.error(panic))
    .then(//recursively call itself with next batch
      _=>
        process(handleBatchResult)(batchSize)(maxFunction)(urls.slice(batchSize))
    );

const handleBatch = results =>{//this will handle results of a batch
  //maybe write successes to file but certainly write failed
  //  you can retry later     
  const successes = results.filter(result=>!isFail(result));
  //failed are the requests that failed
  const failed = results.filter(isFail);
  //To get the failed urls you can do
  const failedUrls = failed.map(([error,url])=>url);
};

const per_batch_1000_max_10_active = 
  process (handleBatch) (1000) (lib.throttle(10));

//start the process
per_batch_1000_max_10_active(largeArrayOfUrls)
.then(
  result=>console.log("Process done")
  ,err=>console.error("This should not happen:".err)
);
在handleBatchResult中,您可以将失败的请求存储到一个文件中,以便稍后重试const[error,uri]=failedResultItem;如果大量请求失败,您应该放弃


handleBatchResult之后有一个.catch,这是您的紧急模式,它不应该在那里失败,因此我建议您使用linux。

如果要处理数千个URL,最好定义一个批大小,并递归调用process函数来处理一个批

最好限制活动连接的数量,您可以使用限制活动连接或在特定时间内每秒仅5次的连接

最后但并非最不重要;如果你使用诺言,你就要确保当一个诺言被拒绝时,不会失去所有的成功。您可以捕获被拒绝的请求并返回失败类型对象,这样它就可以使用此失败类型进行解析

代码如下所示:

const async = require("async");
//lib comes from: https://github.com/amsterdamharu/lib/blob/master/src/index.js
const lib = require("lib");
const request = require("request");

const Fail = function(reason){this.reason=reason;};
const isFail = o=>(o&&o.constructor)===Fail;
const requestAsPromise = fullUri =>
  new Promise(
    (resolve,reject)=>
      request({
        url: fullUri
      }, 
      (err, res, body) => {
        console.log("Request callback fired...");
        if (err || res.statusCode !== 200) reject(err);
        console.log("Success:",fullUri);
        resolve([res,body]);
      })
  )
const process = 
  handleBatchResult =>
  batchSize =>
  maxFunction =>
  urls =>
    Promise.all(
      urls.slice(0,batchSize)
      .map(
        url=>
          maxFunction(requestAsPromise)(url)
          .catch(err=>new Fail([err,url]))//catch reject and resolve with fail object
      )
    )
    .then(handleBatch)
    .catch(panic=>console.error(panic))
    .then(//recursively call itself with next batch
      _=>
        process(handleBatchResult)(batchSize)(maxFunction)(urls.slice(batchSize))
    );

const handleBatch = results =>{//this will handle results of a batch
  //maybe write successes to file but certainly write failed
  //  you can retry later     
  const successes = results.filter(result=>!isFail(result));
  //failed are the requests that failed
  const failed = results.filter(isFail);
  //To get the failed urls you can do
  const failedUrls = failed.map(([error,url])=>url);
};

const per_batch_1000_max_10_active = 
  process (handleBatch) (1000) (lib.throttle(10));

//start the process
per_batch_1000_max_10_active(largeArrayOfUrls)
.then(
  result=>console.log("Process done")
  ,err=>console.error("This should not happen:".err)
);
在handleBatchResult中,您可以将失败的请求存储到一个文件中,以便稍后重试const[error,uri]=failedResultItem;如果大量请求失败,您应该放弃


在handleBatchResult之后有一个.catch,这是您的恐慌模式,它不应该在那里失败,所以我建议您使用linux。

您不是指“每个系列”吗?每一个都是平行的。@JimBaldwin-太好了,谢谢!我错过了那个。这是可行的,但现在我们正在寻找一种不异步的方法。你不是说“每个系列”吗?每一个都是平行的。@JimBaldwin-太好了,谢谢!我错过了那个。这是可行的,但现在我们将研究一种不异步的方法。谢谢,Nicholas。我试过给你贴标签,但没法。此例程将是非常大的CSV上载的一部分。有多少未兑现的承诺就是太多了?如果我有100000张唱片呢?或者…数百万?呃,哦-创建这么多函数时,您可能会遇到调用堆栈限制问题-但回调风格的代码也会出现同样的问题。还有记忆呢?是否要将整个CSV加载到内存中?它合适吗?你可能需要调查一下。你到底需要做什么?我也这么想。现在使用小文件进行测试,但预期会更大
. 我已经通过multer将文件流式传输到API端点。然后我需要处理每一行,将其分割成几个记录,然后将这些记录插入分散在其他几个microservice端点上的表中……因此请求调用。很好。你能再问我一个问题吗?好的。非常感谢!可以在这里找到:谢谢,尼古拉斯。我试过给你贴标签,但没法。此例程将是非常大的CSV上载的一部分。有多少未兑现的承诺就是太多了?如果我有100000张唱片呢?或者…数百万?呃,哦-创建这么多函数时,您可能会遇到调用堆栈限制问题-但回调风格的代码也会出现同样的问题。还有记忆呢?是否要将整个CSV加载到内存中?它合适吗?你可能需要调查一下。你到底需要做什么?我也这么想。现在使用小文件进行测试,但预期会更大。我已经通过multer将文件流式传输到API端点。然后我需要处理每一行,将其分割成几个记录,然后将这些记录插入分散在其他几个microservice端点上的表中……因此请求调用。很好。你能再问我一个问题吗?好的。非常感谢!可以在这里找到: