2013-03-26 85 views
1

我正在使用Node.js的一个简单的应用程序,它需要做的给予有效的URL如何使用Node.js的远程文件下载N多同步

  1. 检索远程页面的HTML以下时,在本地保存。
  2. Spider HTML(使用cheerio)并记录所有JS和CSS文件引用。
  3. 为每个JS/CSS文件发出HTTP请求并通过文件名将其保存到服务器。
  4. 压缩html,css和js文件并将生成的文件流式传输到浏览器。

我有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

a)我不认为有一种方法可以在节点 中执行同步http请求b)同步执行所有操作将会是一个非常糟糕的主意 – DeadAlready 2013-03-26 07:00:01

+0

@DeadAlready:+1对于坏主意,尽管存在https://npmjs.org/package/httpsync – Bergi 2013-03-26 09:25:44

+0

DeadAlready,要求必须下载index.html中引用的所有CSS/JS文件,以便将它们压缩。在进行之前,所有文件必须存在时,无论是同步还是异步完成都没有区别。 – commadelimited 2013-03-26 13:18:44

回答

7

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

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

为您需要做的CSS文件像我做的JavaScript文件 – 2013-03-26 08:57:13

+0

谢谢你的帮助@khurrum。 – commadelimited 2013-04-03 21:49:05