【问题标题】:How the while loop works with promise and callback function in Nodejs?while 循环如何与 Nodejs 中的 promise 和回调函数一起工作?
【发布时间】:2021-03-02 00:05:52
【问题描述】:

这是我第一次用 Promise 和回调编写 while 循环。我不知道为什么它会导致无限循环。如何解决?

async function getResult(){
    return new Promise((resolve, reject) => {
        let params ="some input and setting";
        let next = "hasNext";
        let array = [];
        let error = null;
        while(next !== null){
            checkNext(params, function(err,data) { //checkNext is a function to return the current list and check wether there has the next list
                if(err){
                    next = null;
                    error = err;
                }else{
                    next = data.hasNext; // if there is not next list, data.hasNext = null
                    array = array.concat(data.array); // data.array return the current list
                }
            });
        }
        if(error !== null){
            reject(error);
        }else{
            resolve(array); // I want to return all lists
        }
       
    });
}

【问题讨论】:

    标签: node.js loops promise callback


    【解决方案1】:

    它会导致无限循环,因为 checkNext() 是异步且非阻塞的,因此您的 while() 将永远运行,甚至在对 checkNext() 的一次调用有机会完成并调用其回调之前。

    你永远不会使用 while() 循环等待一些异步事情在 Javsacript 中完成(除了await,如下所示),因为使用 nodejs 的事件驱动架构,while 循环永远不会将控制返回给事件循环所以没有异步操作永远无法处理其完成事件,因此您等待的事情永远不会有机会发生。如果您使用await 等待连接到您的异步事件的承诺,情况会有所不同(如下所示)。然后,您可以成功使用while() 循环。

    对于要使用 Promise 的异步操作,您几乎总是希望 Promisify 您的异步操作,因此您的所有控制流都使用 Promise,而不是简单的回调,因为两者不能很好地混合。这是我的建议:

    const { promisify } = require('util');
    
    const checkNextP = promisify(checkNext);
    
    async function getResult() {
        let params = "some input and setting";
        let next = "hasNext";
        let array = [];
        while (next !== null) {
            let data = await checkNextP(params);
            next = data.hasNext;               // if there is not next list, data.hasNext = null
            array = array.concat(data.array);  // data.array return the current list
        }
        return array;
    }
    

    在这里,while 循环有效,因为我们使用 await 和从 checkNextP() 返回的承诺,并且 await 暂停函数的执行,直到该承诺解决/拒绝。

    更多关于异步函数如何工作的解释

    当我们点击第一个await 时,这个async 函数将自动返回一个promise。调用者将在那时得到这个承诺。然后,当第一个 await 的承诺解决时,函数将恢复,您将获得第一个 data 值,然后执行循环的其余部分。这个过程将重复直到nextnull。此时,您的while() 循环将完成,return array 语句将执行。因为这是一个 async 函数,所以该 return 语句真正做的是解析 async 函数先前返回的承诺,并将 array 设置为该承诺的解析值。

    如果来自checkNextP() 的promise 被拒绝,那么await checkNextP() 将抛出拒绝,因为我们周围没有try/catchasync 函数将自动捕获该抛出并拒绝async 函数之前返回的承诺,导致调用者得到一个承诺拒绝,任何错误 checkNextP() 被拒绝。所以,这里的错误处理也有效。

    getResult()的调用者,只需要这样做:

    getResult().then(results => {
        console.log(results);
    }).catch(err => {
        console.log(err);
    });
    

    或者,调用者也可以在 async 函数本身中并使用 awaittry/catch 来捕获错误。

    【讨论】:

    • 我想写的差不多,但你写得更快。而且更好。我只想留下一个有用的链接供参考:How do I convert an existing callback API to promises?
    • 谢谢,我的朋友。从您的帖子中学到了很多东西。
    • @LiLian - 很高兴为你解释了事情。如果这回答了您的问题,那么您可以通过单击答案左侧的复选标记向社区表明这一点。这也将为您在此处遵循正确的程序赢得一些声誉积分。
    猜你喜欢
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    相关资源
    最近更新 更多