如何使用 nodejs 将异步用于回调?

Posted

技术标签:

【中文标题】如何使用 nodejs 将异步用于回调?【英文标题】:How to use async for callbacks using nodejs? 【发布时间】:2017-07-19 21:54:57 【问题描述】:

一旦我从 clinet 获得搜索字符串,我就有搜索功能,我想遍历文件并匹配 fs 中文件的字符串,我在循环中有问题,我想获取所有匹配结果并将结果发送给客户端。下面试图实现但粘贴有问题的错误。对于异步库的新手,任何帮助将不胜感激。

app.js

app.get('/serverSearch', function (req, res) 
    var searchTxt = req.query.searchTxt;
    dirDirectory.readDirectory(function(logFiles)
        // res.json(logFiles);
        if(logFiles)
            searchFileService.readFile(searchTxt,logFiles,function(lines,err)
                        console.log('Logs',lines);
                          if (err)
                           return res.send();
                           res.json(lines);
                    )

        
    );

    console.log('Search text', searchTxt);
);

service.js

var fs = require('fs');
var path = require('path');
var async = require('async');
var searchStr;
var result = [];


//Async Method
function readFile(str, logFiles, callback) 
    async.series([
        //Load user to get `userId` first
        function(callback) 
            searchStr = str;
            for (var i = 0; i < logFiles.length; i++) 
                if (logFiles[i].filename !== '.gitignore') 
                    fs.readFile('logs/dit/' + logFiles[i].filename, 'utf8', function(err, data) 
                        if (err) 
                            return console.log(err);
                        
                        inspectFile(data);
                    );
                
                callback(result);
            
        ,
        //Load posts (won't be called before task 1's "task callback" has been called)
        function() 
            function inspectFile(data, callback) 
                var lines = data.split('\n'); // get the lines
                lines.forEach(function(line)  // for each line in lines
                    if (line.indexOf(searchStr) != -1)  // if the line contain the searchSt
                        result.push(line);
                        // then log it
                        return line;
                    
                );
            
        
    ], function(err)  //This function gets called after the two tasks have called their "task callbacks"
        if (err) return err;
    );
;

错误

  if (fn === null) throw new Error("Callback was already called.");

【问题讨论】:

【参考方案1】:

你应该使用async.eachSeries method:

function readFile(str, logFiles, callback) 
    async.eachSeries(array, function(item, cb)
       //Process item
       cb(error,item);
    , function(err)
       if (err) 
           console.log("Some error in one of the items");
           callback(err);
        else 
           console.log("All arrays items have been treated successfully");
           callback(null);
       
    );

我建议在使用 async.eachSeries 函数之前加载 userposts

【讨论】:

您的代码正在运行,它打印所有已成功处理的数组,但未将结果发送到客户端 @hussain 现在呢?我已经更新了答案。我不知道您还需要解决对客户端的回调。【参考方案2】:

您应该使用async.map 而不是系列。你错过了了解系列的作用,系列流程请求自上而下。您正试图通过访问系列本身中的一个函数来打破这个链条。哪个是不,不。

例如:

async.series([
    function() 
        let i = 0;
        do 
            console.log("I'm first in the series: ", i);
            i++;
         while (i < 3);
        callback(); // This tells us this function has finished.
    ,
    function() 
        let i = 0;
        do 
            console.log("I'm next in the series: ", i);
            i++;
         while (i < 3);
        callback(); // This tells us this function has finished.
    
]);

这样的输出是:

I'm next in the series: 0

I'm next in the series: 1

I'm next in the series: 2

直到回调被触发,然后它告诉 async 移动到系列数组中的下一个函数。

然后输出将是:

I'm last in the series: 0

I'm last in the series: 1

I'm last in the series: 2

在本系列中,您绝不应该在当前系列之后访问该系列中的函数。所以你永远不应该尝试交叉访问它。

使用async.map,您实际上可以对数组中的每个实体执行操作,这实际上就是您想要做的。

var results = [];
async.map(logFiles, function(logfile, callback) 
    if (logfile.filename !== '.gitignore') 
       fs.readFile('logs/dit/' + logfile.filename, 'utf8', function(err, data) 
           if (err) 
               callback(err, null);
           
           var lines = data.split('\n'); // get the lines
           lines.forEach(function(line)  // for each line in lines
               if (line.indexOf(searchStr) != -1)  // if the line contain the searchSt
                   results.push(line);
                   callback(null, results);
               
           );
    
), function(error, result) 
     results.map(result => 
         console.log(result);
     );
);

另外你应该使用 util.inspect 而不是 console.log,它更干净并且有更多的选择。

这方面的文档有点粗糙,但在这里。 https://caolan.github.io/async/docs.html#map希望对您有所帮助!

【讨论】:

我正在尝试解决您的代码中的一些语法问题 是的,对不起,我混合了 ES6 和 ES5,但它应该接近你需要的。希望对您有所帮助! @hussain 是的,这就是告诉地图继续前进的原因。 得到了你,nodejs 的新手,我试图修复它令人困惑的语法错误,但如果你能帮助修复它,我会很感激它 语法问题解决后出现此错误if (fn === null) throw new Error("Callback was already called."); ^ Error: Callback was already called. 与我的代码相同的错误

以上是关于如何使用 nodejs 将异步用于回调?的主要内容,如果未能解决你的问题,请参考以下文章

如何优雅的处理Nodejs中的异步回调

如何从请求中返回结果,以及在 NodeJS 中执行异步任务但没有回调之后

nodejs如何从异步回调函数返回想要的值

nodejs基础 -- 回调函数

nodejs学习笔记 --回调函数

Nodejs学习笔记