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

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

  1. 检索远程页面的HTML,保存在本地。
  2. 蜘蛛的HTML(使用cheerio)并logging所有的JS和CSS文件引用。
  3. 为每个JS / CSS文件创buildHTTP请求并通过文件名将其保存到服务器。
  4. 压缩html,css和js文件并将结果文件stream式传输到浏览器。

我有1和2个工作,而#3的前半部分,但我遇到的下载同步性的问题。 我的代码运行得太快,为CSS和JS文件生成文件名,但没有任何内容。 我猜这是因为我的代码不同步。 问题是,我不能预先知道有多less文件可以在ZIP文件生成之前,所有文件都必须在那里。

这是我的应用程序的stream程,因为它目前存在。 我省略了辅助方法,因为它们不会影响同步性。 你们能提供什么我应该做的input吗?

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

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

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

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

 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 async模块

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