Node.js while循环如何与Nodejs中的promise和callback函数一起工作?

Node.js while循环如何与Nodejs中的promise和callback函数一起工作?,node.js,loops,promise,callback,Node.js,Loops,Promise,Callback,这是我第一次用Promise和callback编写while循环。我不知道为什么它会导致无限循环。如何修复它 async function getResult(){ return new Promise((resolve, reject) => { let params ="some input and setting"; let next = "hasNext"; let array = []

这是我第一次用Promise和callback编写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
        }
       
    });
}

它会导致无限循环,因为
checkNext()
是异步和非阻塞的,所以您的
while()
在对
checkNext()
的一次调用有机会完成并调用其回调之前就一直运行

您永远不会使用
while(),while循环从不将控制返回事件循环,因此任何异步操作都无法处理其完成事件,因此您等待的事情永远不会有机会发生。如果您使用
await
等待连接到异步事件的承诺,则情况会有所不同(如下所示)。然后,您可以成功地使用
while()
循环

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

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
函数将自动返回一个承诺。打电话的人会在那时得到承诺。然后,当第一个
wait
的承诺解决时,函数将恢复,您将获得第一个
数据
值,其余循环将执行。此过程将重复,直到
next
null
。此时,将完成
while()
循环,并执行
returnarray
语句。因为这是一个
async
函数,返回语句真正做的是解析
async
函数先前返回的承诺,并将
数组设置为该承诺的解析值

如果来自
checkNextP()
的承诺被拒绝,那么
wait checkNextP()
将抛出拒绝,因为我们没有
try/catch
围绕它,因此
async
函数将自动捕获该抛出,并拒绝
async
函数先前返回的承诺,导致调用者以任何错误获得承诺拒绝
checkNextP()
rejected with。因此,这里的错误处理也很有效

getResult()
的调用方只需执行以下操作:

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

或者,调用者也可以在
async
函数本身中,使用
wait
try/catch
捕捉错误。

这会导致无限循环,因为
checkNext()
是异步和非阻塞的,所以
while()
在调用
checkNext()之前永远运行
有机会完成并调用其回调

您永远不会使用
while(),while循环从不将控制返回事件循环,因此任何异步操作都无法处理其完成事件,因此您等待的事情永远不会有机会发生。如果您使用
await
等待连接到异步事件的承诺,则情况会有所不同(如下所示)。然后,您可以成功地使用
while()
循环

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

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
函数将自动返回一个承诺。打电话的人会在那时得到承诺。然后,当第一个
wait
的承诺解决时,函数将恢复,您将获得第一个
数据
值,其余循环将执行。此过程将重复,直到
next
null
。此时,将完成
while()
循环,并执行
returnarray
语句。因为这是一个
async
函数,返回语句真正做的是解析
async
函数先前返回的承诺,并将
数组设置为该承诺的解析值

如果来自
checkNextP()
的承诺被拒绝,那么
wait checkNextP()
将抛出拒绝,因为我们没有
try/catch
围绕它,因此
async
函数将自动捕获该抛出,并拒绝
async
函数先前返回的承诺,导致调用者以任何错误获得承诺拒绝
checkNextP()
rejected with。因此,这里的错误处理也很有效

getResult()
的调用方只需执行以下操作:

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