如何将 async 与其他异步模块一起使用?

Posted

技术标签:

【中文标题】如何将 async 与其他异步模块一起使用?【英文标题】:How to use async with other asynchronous modules? 【发布时间】:2014-06-18 05:28:41 【问题描述】:

这是一个没有异步的工作测试程序:

var fs = require('fs');
function test() 
    var finalResponse = '', response = '';
    function showFinalResponse() 
        console.log(finalResponse);
    
    function processTheFile(err, data) 
        if (err) 
            finalResponse = 'Could not read the file';
         else 
            response += data;
            response += '</body></html>';
            finalResponse = response;
        
        showFinalResponse();
    
    function readTheFile(exists) 
        if (!exists) 
            finalResponse = 'File does not exist.';
            showFinalResponse();
         else 
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', processTheFile);
        
    
    fs.exists('file.txt', readTheFile);
;
test();

这是我尝试让相同的程序与异步瀑布一起工作。我在如何在异步和 fs 调用中传递回调时遇到问题。

var fs = require('fs');
var async = require('async');
function testAsync() var finalResponse, response = '';
    async.waterfall( [
        function checkIfTheFileExists(done) 
            fs.exists('file.txt', done);
        ,
        function readTheFile(err, exists, done) 
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', done);
        ,
        function processTheFile(err, data, done) 
            response += data;
            response += '</body></html>';
            finalResponse = response;
            done(null);
         ],
        function showFinalResponse(err) 
            if (err) 
                if (err.code === 'ENOENT')   // intended to test for file is missing.
                    finalResponse = 'File does not exist.';
                 else  // any other errors.
                    finalResponse = 'Could not read the file';
                
                console.log(err);
            
            console.log(finalResponse);
        
    );

testAsync()

我无法让异步版本工作。我对回调的去向感到困惑。

【问题讨论】:

【参考方案1】:

这是我的最终工作版本(以防它帮助其他人)。再次感谢您的帮助!

var fs         = require('fs');
var async      = require('async');
var addErrParm = function (err, done) return function(exists) 
    done(err, exists);

function testAsync() var finalResponse, response = '';
    function checkIfTheFileExists(done) 
        fs.exists('file.txt', addErrParm(null, done));
    
    function readTheFile(exists, done) 
        if (!exists) 
            done('notFound');
         else 
            response += '<!DOCTYPE html><html lang="en-US"><head></head><body>';
            fs.readFile('file.txt', 'utf8', done);
        
    
    function processTheFile(data, done) 
        response += (data || 'The file is empty') + '</body></html>';
        finalResponse = response;
        done(null);
    
    function showFinalResponse(err) 
        if (err) 
            finalResponse = (err === 'notFound' ? 'File does not exist.' : 'Could not read the file');
        
        console.log(finalResponse);
    
    async.waterfall([ checkIfTheFileExists,
                      readTheFile,
                      processTheFile
    ], showFinalResponse);

testAsync()

所以基本上,异步需要从除最终回调之外的所有函数中删除 err 参数(第一个参数),并且需要在除最终回调之外的所有函数上添加一个回调('done')作为额外参数。

另外,如果没有像 fs.exists 这样的 err 参数,您必须创建一个函数来模拟 err 参数,以便 async 可以将其删除。

【讨论】:

【参考方案2】:

fs.exists 很奇怪,因为它没有向其回调函数提供错误参数。相反,它只提供一个exists 参数来指示是否找到了文件。据推测,如果有错误,exists 将是false。因此,您需要将其回调包装在您自己的函数中,以便您可以为waterfall 回调提供单独的错误参数:

async.waterfall( [
    function checkIfFileExists(done) 
        fs.exists('file.txt', function(exists)  done(null, exists); );
    ,
    function makeSureFileExists(exists, done) 
    ...

请注意 the docs 中的警告,但通常不应使用 fs.exists

【讨论】:

我确实看到了该警告,但我正在使用它,因为我不想在某些情况下打开文件。我只想知道它是否存在。 请在下面的答案中查看我的最终版本。有什么问题吗?【参考方案3】:
fs.exists('file.txt', done(null));

这会立即调用done。您需要将实际的done 函数传递给fs.exists

fs.exists('file.txt', done);

其他人也一样。

【讨论】:

@ChrisG.:fs.exists 接受回调,如果有错误则将其传递给错误,如果没有则将 null 传递给它。在回调之前你不知道是否有错误。传递done 与传递function (error, result) done(error, result); 是一回事。 @ChrisG.: processFileFile 也不会出错。这就是大多数异步函数的用途;如果瀑布的任何部分出现错误,只有最终的回调会得到它,而介于两者之间的将被跳过。 好的,我认为正在取得进展。仍然无法正常工作。我编辑了问题以显示我最近的尝试。

以上是关于如何将 async 与其他异步模块一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

使用 async_hooks 模块进行请求追踪

如何将 RestSharp 与 async/await 一起使用

如何将异步与 ForEach 一起使用?

将 Func 委托与 Async 方法一起使用

如何将异步等待与 https 发布请求一起使用

嵌套在 async.js 瀑布中的异步函数