recursion函数的callback

以下代码用于从我们的Web应用程序获取.zip文件。 该文件是通过安全地closures另一个应用程序然后进行压缩生成的,最后发送下载。

 var dl = function() { request({ method: 'GET', uri: 'some_url', headers: { 'User-Agent': 'Scripted-Download' }, encoding: null, jar: true }, function(err, res, body) { if (err) throw(err) if (res.headers['content-type'] === 'application/zip;charset=utf-8') { process.stdout.write('\rDownloading file ..') var id = uuid.v4() , file = path.resolve(__dirname, '../../' + id + '.zip') fs.writeFile(file, body, function(err) { if (err) throw(err) process.stdout.write('\rFile downloaded ' + id + '.zip') process.exit(0) }) } else { process.stdout.write('\rAwaiting file ..') setTimeout(dl(), 30 * 1000) } }) } 

这按预期工作。 但是,我需要从另一个脚本使用这个。 所以上面的代码返回一个下载的文件的id ,然后从另一个脚本中,我可以提取.zip ,并将提取的文件放在一个具有相同id的目录中。 这些文件将被提供下载。

编辑本质上,我需要执行此脚本,提取内容时,下载然后加载与res.render()前面的两个步骤完成时的用户界面。 这需要用id完成,以便两个用户不会创build冲突的文件。

正如评论中所提到的,承诺应该使这一点变得简单。 首先promisify你需要的asynchronousfunction:

 function makeRequest(parameters) { return new Promise(function (resolve, reject) { request(parameters, function (err, res, body) { if (err) { reject (err); } else { resolve({ res: res, body: body }); } }); }); } function writeFile(file, body) { return new Promise(function (resolve, reject) { fs.writeFile(file, body, function(err) { if (err) { reject(err); } else { resolve(); } }); }); } function timeout(duration) { return new Promise(function (resolve) { setTimeout(resolve, duration); }); } 

然后使用它们。

 var dl = function () { return makeRequest({ method: 'GET', uri: 'some_url', headers: { 'User-Agent': 'Scripted-Download' }, encoding: null, jar: true }).then(function (result) { if (result.res.headers['content-type'] === 'application/zip;charset=utf-8') { process.stdout.write('\rDownloading file ..') var id = uuid.v4() , file = path.resolve(__dirname, '../../' + id + '.zip'); return writeFile(file, result.body) .then(function () { return id; }); } else { process.stdout.write('\rAwaiting file ..'); return timeout(30 * 1000).then(dl); } }); } dl().then(function (id) { process.stdout.write('\rid is: ' + id); }); 

您可以使用asynchronous实用程序库,如asynchronous 。

你正在寻找的模式似乎是瀑布模式。 这将允许您将需要的数据从一个任务传递到另一个任务。

 function requestFile(cb){ request({ method: 'GET', uri: 'some_url', headers: { 'User-Agent': 'Scripted-Download' }, encoding: null, jar: true }, function(err, res, body) { if (err) throw(err) if (res.headers['content-type'] === 'application/zip;charset=utf-8') { process.stdout.write('\rDownloading file ..'); cb(null, body); } else{ process.stdout.write('\rAwaiting file ..'); setTimeout(requestFile, 30 * 1000) } }); } function saveFile(body, cb){ var id = uuid.v4() , file = path.resolve(__dirname, '../../' + id + '.zip') fs.writeFile(file, body, function(err) { if (err) throw(err) process.stdout.write('\rFile downloaded ' + id + '.zip'); cb(null, id); }) } function render(id, cb) { //do what ever you need with your id cb(); } async.waterfall([ requestFile, saveFile, render ], function(err){ }); 

顺便说一句,我build议你直接从服务器的数据stream到磁盘,而不是收集在一个缓冲区,然后保存。

您可以在请求对象上创builddata侦听器,然后直接将它们stream式传输到磁盘,甚至可以使用request.pipe(file)

例:

 function streamFile(){ var id = uuid.v4() , file = path.resolve(__dirname, '../../' + id + '.zip'); var stream = fs.createWriteStream(file); stream.on('error', function(err){ throw err; }).on('close', function(){ process.stdout.write('\rFile downloaded ' + id + '.zip') }); request({ method: 'GET', uri: 'some_url', headers: { 'User-Agent': 'Scripted-Download' }, encoding: null, jar: true }).on('error', function(err) { throw(err) }).on('response', function(res){ if (res.headers['content-type'] === 'application/zip;charset=utf-8') { process.stdout.write('\rDownloading file ..'); cb(null, body); } else{ process.stdout.write('\rAwaiting file ..'); res.destroy(); setTimeout(streamFile, 30 * 1000) } }).pipe(stream); }