如何在递归完成后才能解析Promise?

23k*_*23k 0 javascript recursion promise

我有一个问题让这个逻辑工作,我甚至不知道它是否可能或我是否正确使用promises.

我有第一个函数,它接受一个I​​D列表,用于发出请求以提取特定的异步数据.我一次只能拉1000,所以如果列表包含1000以上,我必须通过它来解决.

我正在寻找的是 - 对于你需要递归的每个选项,调用递归函数,等待结果,然后将它们推送到列表.获取所有数据后,请回复数据.

async function getData () {
    .... 
    // Inside condition that determines it needs to recurse
    let _data = await _getOptions(id, data, 0);
    dataList.push(_data);
    ...
    // Eventually, return the data
    res.json(dataList);
}
Run Code Online (Sandbox Code Playgroud)

此函数通过列表进行递归,并且在引入所有数据后应该解析.

let rData = [];
function _getOptions(id, data, offset) {
    return new Promise((resolve, reject) => {
        if (data.length < 1000) {
            return resolve(rData);
        }
        let fields = { fields: `id, key_value, label, condition_value`, offset: offset, limit: 1000 };
        options.getOptionsWithFilter(id, fields, (err, data) => {
            rData.push(data);
            _getOptions(id, data, offset + 1000);
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

由于控制台中抛出的错误,这似乎不起作用,这表明它正在返回undefined.我猜这个问题是我在这里使用了错误的承诺.但我一直在努力想出另一种解决方案._data在我继续前进之前,我需要在变量中返回所有数据.

tri*_*cot 5

你的诺言构造回调应该总是产生一个呼叫resolve(或reject),但是当你在做递归调用,你永远不要叫resolve那个特定的承诺.所以称之为,像这样:

resolve(_getOptions(id, data, offset + 1000));
Run Code Online (Sandbox Code Playgroud)

我还认为组合结果数据块的方法是错误的:您可以将数组作为嵌套数组推送到最终数组中.我希望你需要将块连接成一维数组.

data变量的使用存在一个问题:你将它用于传递给_getOptions函数的东西(不确定最初是什么),也用于提供getOptionsWithFilter.我认为后面的数据实际上是data你正在处理的唯一数据.那么你就不需要把它传递给了_getOptions.

避免使用全局rData变量也是可取的.由于您只将其设置为空数组一次,因此您可能无法为要进行的任何下一个请求清除它.

相反,让最终的承诺产生最后的数据块,然后将之前的块添加到它:

function _getOptions(id, offset = 0) { // No data argument!
    return new Promise((resolve, reject) => {
        let fields = { fields: `id, key_value, label, condition_value`, 
                       offset: offset, limit: 1000 };
        options.getOptionsWithFilter(id, fields, (err, data) => {
            if (data.length < 1000) { // Perform the check when you have the data
                return resolve(data); // just this chunk
            }
            resolve(_getOptions(id, offset + 1000) // Don't pass data
                       // prepend this data to the data that the recursive 
                       // promise will provide
                       .then(rData => data.concat(rData))
            );
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

你这样称呼它:

_data = await _getOptions(id);
Run Code Online (Sandbox Code Playgroud)

替代方案:一个承诺

您还可以选择在一个Promise构造函数回调中执行异步循环("递归调用"):

function _getOptions(id) { // No data argument!
    return new Promise((resolve, reject) => {
        let rData = [];
        (function loop(offset) {
            let fields = { fields: `id, key_value, label, condition_value`, 
                           offset: offset, limit: 1000 };
            options.getOptionsWithFilter(id, fields, (err, data) => {
                rData = rData.concat(data);
                if (data.length < 1000) { // Perform the check when you have the data
                    return resolve(rData); // All retrieved data
                }
                loop(offset + 1000); // Collect more
            });
        })(0); // Call immediately
    });
}
Run Code Online (Sandbox Code Playgroud)