Node.js异步下载多个文件

时间:2015-11-27 08:39:59

标签: javascript node.js asynchronous

在尝试获取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");
        }
    }
};

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

2 个答案:

答案 0 :(得分:0)

首先尝试简单,看起来您复制粘贴代码并且完全不了解它们的作用。

做一个简单的循环,获取网址,并打印一些东西。

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);
}

将异步提取所有网址。您可以观察到响应没有按顺序到达,但仍然可以正确处理。

异步的困难不在于事情是并行的,因为你只需编写一个单独的任务,并执行多次。当您需要在继续之前等待所有任务完成时,它变得复杂。为此,请查看promises

答案 1 :(得分:0)

这是我开始使用的内容。确定每个下载都是异步调用的,它们都是相互独立的。

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);
                    })
    }
  });