同步使用Node.js下载N个远程文件

时间:2013-03-26 04:53:14

标签: javascript node.js asynchronous express synchronous

我正在使用Node.js创建一个简单的应用程序,当给出有效的URL时需要执行以下操作

  1. 检索远程页面的HTML,将其保存在本地。
  2. 蜘蛛HTML(使用cheerio)并记录所有JS和CSS文件引用。
  3. 为每个JS / CSS文件发出HTTP请求,并按文件名将其保存到服务器。
  4. 压缩html,css和js文件,并将生成的文件流式传输到浏览器。
  5. 我有1个和2个工作,而#3的前半部分但是我遇到了下载同步特性的问题。我的代码运行得太快,并为CSS和JS文件生成文件名,但没有内容。我猜这是因为我的代码不是同步的。问题是我事先不知道可能有多少文件,所有这些文件都必须存在才能生成ZIP文件。

    这是我的应用程序当前存在的流程。我遗漏了辅助方法,因为它们不会影响同步性。你们中的任何人都可以提供我应该做什么的意见吗?

    http.get(fullurl, function(res) {
        res.on('data', function (chunk) {
            var $source = $(''+chunk),
                js = getJS($source, domain),
                css = getCSS($source, domain),
                uniqueName = pw(),
                dir = [baseDir,'jsd-', uniqueName, '/'].join(''),
                jsdir = dir + 'js/',
                cssdir = dir + 'css/',
                html = rewritePaths($source);
    
            // create tmp directory
            fs.mkdirSync(dir);
    
            console.log('creating index.html');
    
            // save index file
            fs.writeFileSync(dir + 'index.html', html);
    
            // create js directory
            fs.mkdirSync(jsdir);
    
            // Save JS files
            js.forEach(function(jsfile){
                var filename = jsfile.split('/').reverse()[0];
                request(jsfile).pipe(fs.createWriteStream(jsdir + filename));
                console.log('creating ' + filename);
            });
    
            // create css directory
            fs.mkdirSync(cssdir);
    
            // Save CSS files
            css.forEach(function(cssfile){
                var filename = cssfile.split('/').reverse()[0];
                request(cssfile).pipe(fs.createWriteStream(cssdir + filename));
                console.log('creating ' + filename);
            });
    
            // write zip file to /tmp
            writeZip(dir,uniqueName);
    
            // https://npmjs.org/package/node-zip
            // http://stuk.github.com/jszip/
    
        });
    }).on('error', function(e) {
        console.log("Got error: " + e.message);
    });
    

1 个答案:

答案 0 :(得分:8)

通过请求模块下载文件的方式是异步的

request(cssfile).pipe(fs.createWriteStream(cssdir + filename));

而不是像你需要做的那样下载创建一个单独的函数

function download (localFile, remotePath, callback) {
var localStream = fs.createWriteStream(localFile);

var out = request({ uri: remotePath });
out.on('response', function (resp) {
    if (resp.statusCode === 200){
        out.pipe(localStream);
        localStream.on('close', function () {
            callback(null, localFile);
        });
    }
    else
        callback(new Error("No file found at given url."),null);
})
};

您需要使用colan https://github.com/caolan/async for

的异步模块
// Save JS files
    async.forEach(js,function(jsfile,cb){
        var filename = jsfile.split('/').reverse()[0];
        download(jsdir + filename,jsfile,function(err,result){
          //handle error here

          console.log('creating ' + filename);
          cb();
        })                        
    },function(err){
     // create css directory
    fs.mkdirSync(cssdir);

    // Save CSS files
    css.forEach(function(cssfile){
        var filename = cssfile.split('/').reverse()[0];
        request(cssfile).pipe(fs.createWriteStream(cssdir + filename));
        console.log('creating ' + filename);
    });

    // write zip file to /tmp
    writeZip(dir,uniqueName);
    });