【问题标题】:node.js: how to implement a routing method with an async call inside a forEach loop?node.js:如何在 forEach 循环中使用异步调用实现路由方法?
【发布时间】:2015-12-11 23:41:29
【问题描述】:

我必须实现这样的逻辑:

var express = require('express'),
    request = require('request');

var array = [
  { url: 'http://www.example1.com' },
  { url: 'http://www.example2.com' },
];

express.Router().get('/job', function (req, res) {
  results = [];
  array.forEach(function (item) {
    request(item.url, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        results.push(body);
      }
  });
  res.json(results); // <== wrong, results array is empty, here...
});

如何调用 res.json(results) 以确保 forEach 循环已结束?

更新:它不是建议答案的重复!

当所有请求完成时我需要 res.json(),而当 forEach 循环完成时 not... :-(

【问题讨论】:

标签: javascript node.js asynchronous


【解决方案1】:

您可以使用asnyc series 来实现此目的。像这样的:

var express = require('express'),
    request = require('request');
    async = require('async);

...

async.series([
    function(callback) {
        request('http://www.example1.com', function (error, response, body) {
            if (!error && response.statusCode == 200) {
                callback(null, body);
            }
        });
    },
    function(callback) {
        request('http://www.example2.com', function (error, response, body) {
            if (!error && response.statusCode == 200) {
                callback(null, body);
            }
        });
    }
], function(err, res) {
    res.json(res);
});

【讨论】:

  • 在现实生活中,我没有 2 个请求,但有数千个...... :-(
  • 我不认为等待数千个请求完成是个好主意。也许你应该改变你的逻辑并寻找一个后台进程来处理它们?
  • 好点!在哪里可以找到有关将节点作为后台进程运行的一些信息?
  • 谢谢...我想我不会采用建议的方法:我只会将节点进程作为 cron 作业运行;进程状态将在数据库上共享...
【解决方案2】:

实现此目的的简单方法:

var express = require('express'),
    request = require('request');

var array = [
  { url: 'http://www.example1.com' },
  { url: 'http://www.example2.com' },
];

//store number of completed calls
var completed = 0;

express.Router().get('/job', function (req, res) {
  results = [];
  array.forEach(function (item) {
    request(item.url, function (error, response, body) {
      if (!error && response.statusCode == 200) {
        results.push(body);

        completed = completed + 1; //iterate counter
        onComplete(); //attempt completion
      }
  });

  function onComplete(){
    if(completed != array.length) {
      return;
    }
    res.json(results); 
    // ... rest of code that relies on results
  };

});

【讨论】:

    【解决方案3】:

    你应该使用承诺! (此示例适用于最新版本的节点,因为支持原生承诺)

    var arrayPromises = [];
    
    array.forEach(function (item) {
    
       arrayPromises.push(new Promise(function(resolve, reject) {
           request(item.url, function (error, response, body) {
              if (!error && response.statusCode == 200) {
                 resolve(body);
              }else{
                resolve();
              }
           });
       }));
    });
    
    Promise.all(arrayPromises).then(function(results){
      res.json(results);
    });
    

    【讨论】:

      猜你喜欢
      • 2014-10-09
      • 1970-01-01
      • 2017-06-16
      • 2013-02-16
      • 1970-01-01
      • 2019-03-24
      • 2021-08-14
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多