回调递归函数

时间:2016-10-26 09:11:59

标签: javascript node.js recursion requestjs

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

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()的UI。这需要使用id来完成,这样两个用户就不会创建冲突的文件。

2 个答案:

答案 0 :(得分:3)

正如评论中所提到的,承诺应该让这很容易。首先宣传您需要的异步功能:

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

答案 1 :(得分:0)

您可以使用异步实用程序库,例如async

您正在寻找的模式似乎是waterfall模式。 这样您就可以将所需的数据从一个任务传递到另一个任务。

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){

});

顺便说一句,我建议您将数据从服务器直接流式传输到磁盘,而不是将其全部收集到缓冲区中,然后保存。

您可以在请求对象上创建data侦听器,然后将它们直接流式传输到磁盘,甚至只需使用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);
}