javascript - 如何仅在递归完成后才进行 Promise 解析?

标签 javascript recursion promise

我在让这个逻辑发挥作用时遇到了问题,我什至不知道这是否可能,或者我是否在这里正确使用了 promise 。

我有第一个函数,它接受 ID 列表,这些 ID 列表用于发出提取特定异步数据的请求。我一次只能拉入 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);
}

此函数在列表中递归,并且应该在所有数据都被拉入后解析。

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);
        });
    });
}

由于控制台中抛出错误,这似乎不起作用,这对我来说意味着它返回了未定义。我猜问题是我在这里使用了错误的 promise 。但我一直在努力想出另一个解决方案。我需要将所有数据返回到 _data 变量中,然后才能继续。

最佳答案

您的 Promise 构造函数回调应该始终导致对 resolve(或 reject)的调用,但是当您继续进行递归调用时,您永远不会对特定 promise 调用resolve。所以这样调用它:

resolve(_getOptions(id, data, offset + 1000));

我还认为您组合结果数据 block 的方式是错误的:您会将数组作为嵌套数组推送到最终数组中。我希望您需要将 block 连接成一维数组。

使用 data 变量存在问题:您将它用于传递给 _getOptions 函数的内容(不确定最初是什么),也适用于 getOptionsWithFilter提供。我认为后面的数据实际上是您正在处理的唯一数据。因此,您不需要将其传递给 _getOptions

还建议避免使用全局 rData 变量。由于您只将其设置为空数组一次,因此您可能会面临无法为您想要发出的任何下一个请求清除它的风险。

相反,让最终的 promise 产生最终的数据 block ,然后将之前的数据 block 添加到它前面:

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))
            );
        });
    });
}

你可以这样调用它:

_data = await _getOptions(id);

替代方案:一个 Promise

您还可以选择在一个 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
    });
}

关于javascript - 如何仅在递归完成后才进行 Promise 解析?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48693829/

相关文章:

javascript - 一个 promise 的 mysql 模块将如何与 NodeJS 一起工作?

javascript - Eclipse 在多行中键入代码

javascript - 表单提交时出现 jquery 错误

javascript - 传递动态 Javascript HTML 的 ID

无法理解for循环中的递归

python - 如何在 Python 2.7 中实现迭代函数的递归函数?

php - 得到n深类别树后的多维数组

javascript - Angular 服务 foreach $q.promise

javascript - 调用一个包含来自另一个函数的 Promise 的函数

javascript - 通过正则表达式验证电子邮件