gpt4 book ai didi

javascript - 异步递归函数

转载 作者:行者123 更新时间:2023-12-03 02:46:35 25 4
gpt4 key购买 nike

我正在尝试创建一个 Node js alexa 应用程序来控制我的本地 kodi 实例。我正在使用Node-Kodi作为 JsonRPC API 的包装器。在整个应用程序中,我一直使用异步/等待,没有任何问题。我的代码可以看here在我的公共(public)仓库上。

当我尝试执行递归异步函数时遇到问题。

app.intent("AddonInfoTest",
{
"slots": {"ADDON": "ADDON_SLOT"},
"utterances": ["get info for +ADDON+"]
},
async function(request, response) {
let addon = await kodi.addons.getAddonDetails({
'addonid': 'plugin.video.youtube',
'properties': ['path']
});

console.log(addon.addon.path);

let addonMenu = await kodi.files.getDirectory('plugin://plugin.video.youtube');

let menu = buildAddonMenu(addonMenu);

console.log('menu: ' + JSON.stringify(menu));
}
);

function buildAddonMenu(menu, depth = 0)
{
var addonMenu = {};
var subMenu = {};

menu.files.forEach(async function(file) {
addonMenu[file.label] = {
'link': file.file
}

console.log(file);
console.log(depth)

if (file.filetype == 'directory' && !file.label.match(/^next page.*/i) && depth <= constants.addon_menu_max_depth) {
try {
let subMenu = await kodi.files.getDirectory(file.file);
if (typeof subMenu !== 'undefined' && 'files' in subMenu) {
console.log('Building Sub Menu for ' + file.label);
// console.log('SubMenu: ' + JSON.stringify(subMenu));
addonMenu[file.label]['sub_menu'] = buildAddonMenu(subMenu, depth +1);
}
} catch (error) {
console.error(error);
}
}
});

return addonMenu;
}

似乎发生的情况是,我仅在第一级之后就获得了返回值,并且该函数不等待构建子菜单。

以 youtube 插件为例,控制台输出如下所示:

[2018-01-02T22:49:58.435Z] { file: 'plugin://plugin.video.youtube/sign/in/',
filetype: 'directory',
label: '[B]Sign In[/B]',
type: 'unknown' }
[2018-01-02T22:49:58.436Z] 0
[2018-01-02T22:49:58.437Z] { file: 'plugin://plugin.video.youtube/special/popular_right_now/',
filetype: 'directory',
label: 'Popular right now',
type: 'unknown' }
[2018-01-02T22:49:58.437Z] 0
[2018-01-02T22:49:58.438Z] { file: 'plugin://plugin.video.youtube/kodion/search/list/',
filetype: 'directory',
label: 'Search',
type: 'unknown' }
[2018-01-02T22:49:58.438Z] 0
[2018-01-02T22:49:58.439Z] { file: 'plugin://plugin.video.youtube/special/live/',
filetype: 'directory',
label: 'Live',
type: 'unknown' }
[2018-01-02T22:49:58.439Z] 0
[2018-01-02T22:49:58.442Z] { file: 'plugin://plugin.video.youtube/config/youtube/',
filetype: 'directory',
label: 'Settings',
type: 'unknown' }
[2018-01-02T22:49:58.442Z] 0
[2018-01-02T22:49:58.442Z] menu: {"[B]Sign In[/B]":{"link":"plugin://plugin.video.youtube/sign/in/"},"Popular right now":{"link":"plugin://plugin.video.youtube/special/popular_right_now/"},"Search":{"link":"plugin://plugin.video.youtube/kodion/search/list/"},"Live":{"link":"plugin://plugin.video.youtube/special/live/"},"Settings":{"link":"plugin://plugin.video.youtube/config/youtube/"}}
[2018-01-02T22:49:59.171Z] Building Sub Menu for Search
[2018-01-02T22:49:59.171Z] { file: 'plugin://plugin.video.youtube/kodion/search/input/',
filetype: 'directory',
label: '[B]New Search[/B]',
type: 'unknown' }
[2018-01-02T22:49:59.171Z] 1
[2018-01-02T22:49:59.171Z] { file: 'plugin://plugin.video.youtube/kodion/search/query/?q=minecraft',
filetype: 'directory',
label: 'minecraft',
type: 'unknown' }
[2018-01-02T22:49:59.171Z] 1
[2018-01-02T22:49:59.172Z] { file: 'plugin://plugin.video.youtube/kodion/search/query/?q=Hello+World',
filetype: 'directory',
label: 'Hello World',
type: 'unknown' }
[2018-01-02T22:49:59.172Z] 1
[2018-01-02T22:49:59.172Z] { file: 'plugin://plugin.video.youtube/kodion/search/query/?q=hello+world',
filetype: 'directory',
label: 'hello world',
type: 'unknown' }

我不是 JavaScript 开发人员,而是 PHP 开发人员,因此我很可能没有正确使用异步函数。请有人指出我正确的方向。

完整代码可以在 Branch 上找到

最佳答案

buildAddonMenu 需要是一个 async 函数,并使用 await 运算符调用。尽管菜单可能会继续异步构建(因为 buildAddonMenu 返回一个可以稍后更新的对象),但尝试在同步调用 buildAddonMenu 后立即渲染或检查菜单将失败 - 您只能获得由同步调用中提供的数据组成的第一级菜单项。

因此每次调用 buildAddonMenu 都应采用以下形式

 menuObject = await buildAddonMenu(....)

将其包含在 app.Intent 调用中。

对上述内容进行更改后,控制语句

 menu.files.forEach(async function(file) {...}

显然想要为目录中的每个文件执行异步函数。提供的匿名函数确实需要async才能在函数体中使用await - 但forEach不会等待它对异步函数完成。

Using async/await with a forEach loop有多种解决方案来等待异步调用在循环中完成。如果按顺序添加已完成的子菜单是可以接受的,那么最简单(且可接受)的解决方案可能是创建一个实际的 for 循环,该循环等待异步函数调用(使用 await)处理 menu.files 条目的循环体。

一般来说,请注意 for( ... in ...) 循环返回可枚举的继承属性,并且不建议通过对象的本地自有属性进行迭代。使用 for( ... of ...) 甚至标准的 for(...;...;...) 循环来代替。

关于javascript - 异步递归函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48069124/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com