【问题标题】:Node.js Downloading multiples files asynchronouslyNode.js异步下载多个文件
【发布时间】:2015-11-27 08:39:59
【问题描述】:

在尝试掌握 node.js 异步编码风格的过程中,我决定编写一个程序来读取包含一堆 URL 的文本文件来下载和下载每个文件。我开始编写一个只下载一个文件的函数(效果很好),但是在扩展下载多个文件的逻辑时遇到了麻烦。

代码如下:

var http     = require("http"),
    fs       = require("fs"),
    input    = process.argv[2],
    folder   = "C:/Users/Wiz/Downloads/",
    regex    = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/,
    urls     = null,
    url      = "",
    filename = "";

fs.readFile(input, "utf8", function(e, data) {
    console.log("Reading file: " + input);
    if (e) console.log("Got error:" + e.message);
    urls = data.split("\n");
    for (var i = urls.length; i--;) {
        url = urls[i];
        if (!url.match(regex)) continue;
        filename = folder + url.substring(url.lastIndexOf('/') + 1);
        downloadQueue.addItem(url, filename);
    }
});

var downloadQueue = {
    queue: [],
    addItem: function(p_sSrc, p_sDest) {
        this.queue.push({
            src: p_sSrc,
            dest: p_sDest
        });
        if (this.queue.length === 1) {
            this.getNext();
        }
    },
    getNext: function() {
        var l_oItem = this.queue[0];
        http.get(l_oItem.src, function(response) {
            console.log("Downloading: " + l_oItem.dest);
            var file = fs.createWriteStream(l_oItem.dest);
            response.on("end", function() {
                file.end();
                console.log("Download complete.");
                downloadQueue.removeItem();
            }).on("error", function(error) {
                console.log("Error: " + error.message);
                fs.unlink(l_oItem.dest);
            });
            response.pipe(file);
        });
    },
    removeItem: function() {
        this.queue.splice(0, 1);
        if (this.queue.length != 0) {
            this.getNext();
        } else {
            console.log("All items downloaded");
        }
    }
};

如何构造代码,以便第一次下载的完成可以发出下一次下载的信号。请注意,此练习仅用于学习目的,以了解异步编码的工作原理。在实践中,我确信有更好的工具可以下载多个文件。

【问题讨论】:

  • 什么不起作用?乍一看还不错。
  • 您确实意识到整个异步事情的一部分是您不必等到一个完成才能启动另一个,对吧?
  • Node js 将发送多个下载请求,然后在它们返回时处理它们,如果一个在另一个开始之前返回,或者即使它们以相同的顺序返回,如果你处理它们,它们都无关紧要没错。
  • 它应该可以工作,但我得到一个 ENOENT:没有抛出这样的文件或目录异常。我确实意识到整个异步操作应该可以工作,但事实并非如此,这就是我实现 downloadQueue 来序列化下载的原因。

标签: javascript node.js asynchronous


【解决方案1】:

一开始尝试简单,看起来你复制粘贴代码,完全不明白它们的作用。

做一个简单的循环,获取 url,然后打印一些东西。

var http = require('http');

URL = require('url').parse('http://www.timeapi.org/utc/now?format=%25F%20%25T%20-%20%25N')
URL['headers'] = {'User-Agent': 'Hello World'}


// launch 20 queries asynchronously
for(var i = 0; i < 20; i++) {
  (function(i) {
    console.log('Query ' + i + ' started');
    var req = http.request(URL, function(res) {
      console.log('Query ' + i + ' status: ' + res.statusCode + ' - ' + res.statusMessage);
      res.on('data', function(content){
        console.log('Query ' + i + ' ended - ' + content);
      });
    });

    req.on('error', function(err) {
      console.log('Query ' + i + ' return error: ' + err.message);
    });

    req.end();
  })(i);
}

所有的 url 都将被异步获取。您可以观察到响应没有按顺序到达,但仍被正确处理。

异步的难点在于不能并行处理,因为你只是像一个任务一样编写,然后多次执行。例如,当您需要等待所有任务完成后再继续时,这会变得很复杂。为此,请查看promises

【讨论】:

  • 我自己编写了每一行代码,所以我明白我在做什么,而不是从其他地方复制和粘贴。只是对为什么它不起作用感到困惑。
【解决方案2】:

这是我开始的。考虑到每次下载都是异步调用的,它们都是相互独立的。

var http     = require("http"),
    fs       = require("fs"),
    input    = process.argv[2],
    folder   = "C:/Users/Wiz/Downloads/",
    regex    = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/,
    urls     = null,
    url      = "",
    filename = "";

fs.readFile(input, "utf8",
  function(e, data) {
    console.log("Reading file: " + input);
    if (e) console.log("Got error:" + e.message);
    urls = data.split("\n");
    for (var i = urls.length; i--;) {
      url = urls[i];
      if (!url.match(regex)) continue;
      filename = folder + url.substring(url.lastIndexOf('/') + 1);
      http.get(url, function(response) {
                      var file =  fs.createWriteStream(filename);
                      response.on("end", function() {
                        file.end();
                      });
                      response.pipe(file);
                    })
    }
  });

【讨论】:

    猜你喜欢
    • 2020-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多