3

背景

我有一个问题,我的承诺没有返回到它的调用函数。我知道这通常会起作用,但不是在递归函数中。正在调用解析,我可以看到该函数FindElementById正在正确找到元素,但是未调用 thenableUpdateMasterMenuItem(result, queuedItem)中的调用。

我在我的代码片段中做什么,我想做什么?

循环一个集合queuedItems并在另一个集合中找到这些项目menuItems。我通过将我要查找的项目的 Id 以及它所在的集合传递给递归函数来做到这一点FindElementById。找到该项目后,我将返回找到的项目并在函数中对其执行其他操作UpdateMasterMenuItem

代码

// Calling Loop
        queuedItems.forEach(function (queuedItem) {
            FindElementById(queuedItem.dataset.id, menuItems).then(function(result) {
                UpdateMasterMenuItem(result, queuedItem);
            });
        });


// Recursive Function
function FindElementById(id, menuItems) {
    return new Promise((resolve) => {
        menuItems.forEach(function (menuItem) {
            if (menuItem.Id === id) {
                return resolve(menuItem);

            } else if (menuItem.Child.length > 0) {
                FindElementById(id, menuItem.Child);
            }
        });
    });
}
4

1 回答 1

2

问题来自else if块:当您自己递归调用该方法时,您还需要在resolve()嵌套的 Promise 解决后调用:否则.then()回调将永远不会触发。

function FindElementById(id, menuItems) {
    return new Promise((resolve) => {
        menuItems.forEach(function (menuItem) {
            if (menuItem.Id === id) {
                return resolve(menuItem);

            } else if (menuItem.Child.length > 0) {
                // You also need to remember to resolve here!
                FindElementById(id, menuItem.Child).then(nestedMenuitem => resolve(nestedMenuitem));
            }
        });
    });
}

但是,有一个问题:promise 只能解决一次因此,如果满足条件,您的承诺实际上会在循环的第一次迭代中得到解决forEach。那是你要的吗?如果 ID 确实是唯一的,或者在重复 ID 的情况下您只想返回第一个实例,那么这没关系。

这让我们回到了我的评论:你的函数没有做任何异步操作,所以完全没有承诺可能更容易做到:

function FindElementById(id, menuItems) {
    let el;
    for (let menuItem of menuItems) {
        if (menuItem.Id === id) {
            el = menuItem;
            break;
        } else {
            el = FindElementById(id, menuItem.Child)
        }
    }

    return el;
}
于 2020-04-19T11:01:57.767 回答