for循环内的回调函数-Nodejs

Posted

技术标签:

【中文标题】for循环内的回调函数-Nodejs【英文标题】:Callback function inside for loop - Nodejs 【发布时间】:2021-05-28 22:48:36 【问题描述】:

希望你今天过得愉快。我最近发现在for 循环中处理回调并不容易。我尝试了几件事,但找不到解决方案。 代码如下:

var book = new Array;
var chapters = Object.keys(epub.spine.contents).length;

for (let i = 0; i < chapters; i++) 
    let cacheArray = [];
    epub.getChapter(epub.spine.contents[i].id, function (err, data) 
        if (err) 
            return console.log(err);
        
        //remove html tags
        let str = data.replace(/<\/?[\w\s]*>|<.+[\W]>/g, '');
        book.push(str)
    )

console.log(book)//returns empty array ofc

这段代码执行后,我需要遍历数组来搜索它的内容。如果不是这样,我的方法是将其发送到数据库。

我的方法如下:

var recursiveChapter = function (n) 
    var book = new Array;
    if (n < chapters) 
        // chapter function
        epub.getChapter(epub.spine.contents[n].id, function (err, data) 
            if (err) 
                throw err
            
            //remove HTML tags
            let str = data.replace(/<\/?[\w\s]*>|<.+[\W]>/g, '');
            book.push(str)
            recursiveChapter(n + 1)
        );
    

//start the recursive function
recursiveChapter(0)
console.log(book)//returns an empty array

我被困住了,想不出一种在不将其存储在数据库中的情况下使用这些数据的方法。 任何帮助将不胜感激。

【问题讨论】:

你能告诉我们你期望这段代码做什么以及你目前面临什么? 为什么不承诺您的getChapter 功能。等待这个方法会更容易 @AliHussam getChapter 来自外部库,所以是的,我可以修改它,但我认为这需要一些时间。 (github.com/julien-c/epub) 这个库顺便说一句。 @arminyahya 这个函数基本上将一个 epub 解析为一个字符串,一旦它完成了,我就可以通过事件发射器与之交互。一旦我在那里,我需要加载每一章并删除 html 标签,将每一章推入一个数组,然后我想用 forEach 循环进行搜索。我遇到的问题是 getChapter 返回一个回调,所以 for 循环继续运行,如果我尝试使用数组,它总是空的,所以我不能继续我刚才提到的过程。 你的函数有一个错误的第一个回调,你可以简单地做util.promisify来承诺它或为此调用编写一个承诺的包装器。 【参考方案1】:

有几种方法可以解决这个问题。一种方法是使用async library,这允许异步运行。并行或串行调用。

例如,我们可以使用async.mapSeries()将一系列异步调用的结果作为一个数组来获取。

您输入您的 id 数组,然后回调将返回一个返回数据的数组,例如,我已经模拟了 getChapter() 函数以让您了解它的工作原理:

// Mock out epub object
const epub =  
    getChapter(id, callback) 
        setTimeout(() => callback(null, "Data for id " + id), 250);
    


let ids = [1,2,3,4];
console.log("Calling async.mapSeries for ids:", ids);
async.mapSeries(ids, epub.getChapter, (err, result) => 
    if (err) 
        console.error(err);
     else 
        console.log("Result:", result)
    
)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/async/3.2.0/async.min.js" integrity="sha512-6K6+H87tLdCWvY5ml9ZQXLRlPlDEt8uXmtELhuJRgFyEDv6JvndWHg3jadJuBVGPEhhA2AAt+ROMC2V7EvTIWw==" crossorigin="anonymous"&gt;&lt;/script&gt;

您也可以承诺 epub 调用并使用 Promise.all 来获取结果,如下所示:

epub =  
    getChapter(id, callback) 
        setTimeout(() => callback(null, "Data for id " + id), 250);
    

 
let ids = [1,2,3,4];

function getChapterPromisified(id) 
    return new Promise((resolve, reject) =>  
        epub.getChapter(id, (err, data) =>  
            if (err) 
                reject(err);
             else 
                resolve(data);
            
        )
    )


// Create a list of promises, one for each call
const promises = ids.map(id => getChapterPromisified(id))
Promise.all(promises)
    .then(result => console.log("Result:", result))
    .catch(error => console.error("An error occurred:", err));

【讨论】:

感谢 Terry 的回复,我使用的函数来自外部库(确切地说是 github.com/julien-c/epub),所以我认为我无法修改它。我的意思是,我当然可以,但这可能需要我一些时间,因为我真的不知道它是如何制作的(这个github.com/julien-c/epub)。你的第一个答案,这可能有效,因为我有办法获得身份证。我要试一试,谢谢。 感谢您测试我的答案!您不必修改该功能,如果您想走承诺路线,也许只需添加一个包装器。如果您使用异步方法,则根本不需要修改函数! 哦,对了,我可以包装它并返回一个承诺,我没有想到这一点。你看,我是人们所说的“菜鸟”,所以我从来没有真正尝试过,但它看起来很有趣,我要去看看。非常感谢。 哦,太好了,试试这些方法。只需测试一下,看看是否适合您! 第二个工作得很好,我遇到了一些问题,只是因为我忘了实际兑现承诺,这让我发疯了几个小时。谢谢你!

以上是关于for循环内的回调函数-Nodejs的主要内容,如果未能解决你的问题,请参考以下文章

将索引从 for 循环传递到 ajax 回调函数 (JavaScript)

在 for 循环中的异步函数调用中有条件地执行回调

js的for循环中出现异步函数,回调引用的循环值总是最后一步的值?

js的for循环中出现异步函数,回调引用的循环值始终是最后的值

nodejs所用的概念(同步,异步,事件驱动,事件循环等)通俗解释

物联网服务NodeJs-5天学习第一天篇④ ——了解NodeJs回调函数和事件驱动机制