对递归函数的回调

Callback on recursive function

本文关键字:回调 递归函数      更新时间:2023-09-26

下面的代码用于从我们的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的目录中。然后这些文件就可以下载了。

EDIT基本上我需要执行这个脚本,在下载时提取内容,然后在前两个步骤完成后用res.render()加载UI。这需要用id来完成,这样两个用户就不会创建冲突的文件。

正如评论中提到的,承诺应该使这变得容易。首先承诺你需要的异步功能:

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

您可以使用async.

等异步实用程序库。

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

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