【问题标题】:Node JS for loop and array push用于循环和数组推送的节点 JS
【发布时间】:2017-08-29 07:27:50
【问题描述】:

我有 1,211,434 个 IP 地址需要转换为地理位置。我找到了一个通过使用 GET 请求来回答这个问题的 api。但问题是,当使用 for 循环时,我无法发送 ip 地址并正确接收描述。

我主要有两个问题:

  1. 就是无法输出ip_and_info数组,找不到原因。谁能告诉我出了什么问题?

  2. 现在,我编写的代码可以检索我需要的所有信息,test_ip.txt 中有大约 200 个 ip 地址。如果我尝试发送所有这 100 万个 IP 地址,会有潜在问题吗?

有人可以给我一些建议吗?

非常感谢。

我的代码如下:

fs = require('fs')
async = require("async")
http = require('http')

ip_and_info = []
// getIPInfo("1.171.58.24")


fs.readFile("../test_ips.txt", "utf-8", (err, content, printArr) => {

    content = content.split("\n")

    async.each(content, (ip) => {
        content = getIPInfo(ip)
        // console.log(ip)
    }, (err) => {
        if (err) {
            console.log(err)
        } else {
            console.log(ip_and_info)
        }
    })

    // for (i in content) {
    //     ((ip) => {
    //         getIPInfo(ip)
    //     })(content[i])
    // }


});



function getIPInfo(ipAddress) {

    options = {
        host: 'freegeoip.net',
        path: '/csv/' + ipAddress
    }

    request = http.get(options, function(response) {
        // console.log('STATUS: ' + response.statusCode)
        // console.log('HEADERS: ' + JSON.stringify(response.headers))

        // Buffer the body entirely for processing as a whole.
        bodyChunks = []
        response.on('data', function(chunk) {

            bodyChunks.push(chunk)

        }).on('end', function() {

            body = Buffer.concat(bodyChunks)
            content = body.toString('ascii')
            ip_and_info.push(content)
            console.log(content)
            return content

        })
    })

    request.on('error', function(e) {
        console.log('ERROR: ' + e.message)
    })
}

非常感谢!

【问题讨论】:

  • 这不是问题,但您的代码正在成为The Horror of Implicit Globals 的牺牲品(这是我贫血的小博客上的帖子) - 声明您的变量。
  • 你需要 promises 将所有异步进程推送到数组中并一起解决
  • 您的代码应该只打印空数组。那是因为您的循环将在 getIPInfo() 解决之前完成执行。正如@VinodLouis 所说,您可以在 Promises 的帮助下处理这个问题。如果您对承诺不满意,请告诉我。我会尝试提出解决方案。

标签: javascript node.js asynchronous callback async.js


【解决方案1】:

我认为您的问题可能是您在每个循环中都重新声明了“内容”变量。

所以也许将循环更改为此,这样您就不会在每次循环执行时重置变量。希望能解决您的问题:

  IPList = content.split("\n")

    async.each(IPList, (ip) => {
        IPGeoLocation = getIPInfo(ip)
        console.log(IPGeoLocation)
    }, (err) => {

至于使用一百万个 IP 进行此操作,只要您的计算机上有足够的内存,我看不出有什么大问题。您可能想添加一个“等待”调用,这样您就不会一直敲击服务器。他们可能会阻止你! 我会通过添加在每次通话之间等待 1 秒

sleep(1000);

获取IP后。

【讨论】:

    【解决方案2】:

    问题出在这一行

    content = getIPInfo(ip)

    getIPInfo 应该是一个异步函数。一种方法是向函数发送回调,并在函数中返回回调中的输出。

    async.each(content, getIPInfo, (err) => {
        if (err) {
            console.log(err)
        } else {
            console.log(ip_and_info)
        }
    })
    

    在getIPInfo函数中

    function getIPInfo(ipAddress, callback) {
      .....
      .....
      ip_and_info.push(content)
      callback();
    }
    

    另外,使用 async.eachSeries 或 async.eachLimit 而不是使用 async.each ,否则它将尝试发送所有 1,211,434 ips 的请求。

    【讨论】:

      【解决方案3】:

      使用承诺。
      使用 letconst 关键字。说真的,隐式全局并不好玩。
      决定是使用' 还是" 并坚持下去,它的可读性更强。

      使用 Promise,无需 async 或您的 ip_and_info 变量。

      'use strict';
      
      const fs = require('fs'),
          http = require('http');
      
      fs.readFile('../test_ips.txt', 'utf-8', (err, content) => {
          content = content.split('\n');
      
          Promise.resolve().then(() => {
              return getAllIPInfo(content);
          }).then((ipsInfos) => {
              console.log('Info:' + ipsInfos);
          }).catch((error) => {
              console.error('Error: ' + error);
          });
      });
      
      function getAllIPInfo(ipsAddress) {
          return new Promise((resolve, reject) => {
              let ipsInfo = [];
              ipsAddress.reduce((previous, current, index, ips) => {
                  return previous.then(() => {
                      return getIPInfo(ips[index]).then((content) => {
                          ipsInfo.push(content);
                          return Promise.resolve();
                      });
                  });
              }, Promise.resolve()).then(() => {
                  resolve(ipsInfo);
              }).catch((error) => {
                  reject(error);
              });
          });
      }
      
      function getIPInfo(ipAddress) {
          return new Promise((resolve, reject) => {
              let options = {
                  host: 'freegeoip.net',
                  path: '/csv/' + ipAddress
              };
      
              http.get(options, function(response) {
                  // console.log('STATUS: ' + response.statusCode)
                  // console.log('HEADERS: ' + JSON.stringify(response.headers))
      
                  // Buffer the body entirely for processing as a whole.
                  let bodyChunks = [];
      
                  response.on('data', function(chunk) {
                      bodyChunks.push(chunk);
                  }).on('end', function() {
                      let body = Buffer.concat(bodyChunks),
                          content = body.toString('ascii');
      
                      resolve(content);
                  });
              }).on('error', function(e) {
                  console.log('ERROR: ' + e.message);
                  reject(e);
              });
          });
      }
      

      【讨论】:

      • 此解决方案将一起发送所有 1,211,434 个 ip 的请求。如果您创建一块 ips 的 Promise 对象并在完成时移动到下一个块,那就更好了。
      • @GolakSarangi:更新为按顺序调用 ips
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 2021-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-13
      • 1970-01-01
      相关资源
      最近更新 更多