如何使用 Promise.all 并以对象作为输入

2024-02-15

我一直在开发一个供自己使用的小型 2D 游戏库,但遇到了一些问题。库中有一个名为 loadGame 的特定函数,它将依赖项信息作为输入(资源文件和要执行的脚本列表)。这是一个例子。

loadGame({
    "root" : "/source/folder/for/game/",

    "resources" : {
        "soundEffect" : "audio/sound.mp3",
        "someImage" : "images/something.png",
        "someJSON" : "json/map.json"
    },

    "scripts" : [
        "js/helperScript.js",
        "js/mainScript.js"
    ]
})

资源中的每个项目都有一个密钥,游戏使用该密钥来访问该特定资源。 loadGame 函数将资源转换为 Promise 对象。

问题是它尝试使用 Promises.all 来检查它们何时准备就绪,但 Promise.all 只接受可迭代对象作为输入 - 所以像我这样的对象是不可能的。

所以我尝试将对象转换为数组,这非常有效,除了每个资源只是数组中的一个元素并且没有识别它们的键。

这是 loadGame 的代码:

var loadGame = function (game) {
    return new Promise(function (fulfill, reject) {
        // the root folder for the game
        var root = game.root || '';

        // these are the types of files that can be loaded
        // getImage, getAudio, and getJSON are defined elsewhere in my code - they return promises
        var types = {
            jpg : getImage,
            png : getImage,
            bmp : getImage,

            mp3 : getAudio,
            ogg : getAudio,
            wav : getAudio,

            json : getJSON
        };

        // the object of promises is created using a mapObject function I made
        var resources = mapObject(game.resources, function (path) {
            // get file extension for the item
            var extension = path.match(/(?:\.([^.]+))?$/)[1];

            // find the correct 'getter' from types
            var get = types[extension];

            // get it if that particular getter exists, otherwise, fail
            return get ? get(root + path) :
                reject(Error('Unknown resource type "' + extension + '".'));
        });

        // load scripts when they're done
        // this is the problem here
        // my 'values' function converts the object into an array
        // but now they are nameless and can't be properly accessed anymore
        Promise.all(values(resources)).then(function (resources) {
            // sequentially load scripts
            // maybe someday I'll use a generator for this
            var load = function (i) {
                // load script
                getScript(root + game.scripts[i]).then(function () {
                    // load the next script if there is one
                    i++;

                    if (i < game.scripts.length) {
                        load(i);
                    } else {
                        // all done, fulfill the promise that loadGame returned
                        // this is giving an array back, but it should be returning an object full of resources
                        fulfill(resources);
                    }
                });
            };

            // load the first script
            load(0);
        });
    });
};

理想情况下,我希望有某种方法来正确管理资源承诺列表,同时仍然保留每个项目的标识符。任何帮助将不胜感激,谢谢。


首先:废弃那个Promise构造函数,这种用法是一种反模式 https://stackoverflow.com/q/23803743/1048572!


现在,解决您的实际问题:正如您所正确识别的那样,您缺少每个值的键。您需要将其传递到每个 Promise 中,以便您可以在等待所有项目后重建对象:

function mapObjectToArray(obj, cb) {
    var res = [];
    for (var key in obj)
        res.push(cb(obj[key], key));
    return res;
}

return Promise.all(mapObjectToArray(input, function(arg, key) {
    return getPromiseFor(arg, key).then(function(value) {
         return {key: key, value: value};
    });
}).then(function(arr) {
    var obj = {};
    for (var i=0; i<arr.length; i++)
        obj[arr[i].key] = arr[i].value;
    return obj;
});

Bluebird 等更强大的库也将提供此功能作为辅助函数,例如Promise.props https://github.com/petkaantonov/bluebird/blob/master/API.md#props---promise.


另外,你不应该使用伪递归load功能。您可以简单地将承诺链接在一起:

….then(function (resources) {
    return game.scripts.reduce(function(queue, script) {
        return queue.then(function() {
            return getScript(root + script);
        });
    }, Promise.resolve()).then(function() {
        return resources;
    });
});
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 Promise.all 并以对象作为输入 的相关文章

随机推荐

  • 手动确认消息:Spring Cloud Stream Kafka

    我想要实现的场景是使用来自 Kafka 的消息 处理它 如果某些条件失败我不希望确认该消息 为此 我在 Spring Cloud Stream 参考文档中找到了 自动提交偏移量 处理消息后是否自动提交偏移量 如果设置为 false 则消息标
  • Android:如何动态使视图具有相同的高度

    我正在 Android 应用程序中制作一张表 现在我无法使视图具有相同的高度 有2个TextViews tmp name and tmp content在每一行中 的高度tmp content取决于的长度course description
  • GitHub Actions 工作流程语法未按预期工作

    我有一个 GitHub 工作流程 当文件按照 图案 abc 被修改 创建 据我了解 这意味着每当 位于以下开头的文件夹的某个子文件夹中的文件abc or 任何以以下内容开头的文件abc 修改后 应触发 GH 操作 然而 当我例如创建一个文件
  • 我可以使用 FluentMigrator 创建 nvarchar(MAX) 列吗?

    Using 流利迁移器 http code google com p fluentmigrator 默认创建一个Column using AsString 结果是nvarchar 255 有没有一种简单的方法 在我修改 FluentMigr
  • 如何将标量树枝过滤器映射到数组

    我有一个简单的浮点数数组 我需要将其显示为逗号分隔的字符串 arr join 是一个糟糕的解决方案 因为精度太低 for val in arr val number format 2 endfor 不好 因为末尾有多余的逗号 我想做这样的事
  • Python-生成特定自相关的数组

    我有兴趣生成一个长度为 N 的数组 或 numpy 系列 它将在滞后 1 处表现出特定的自相关性 理想情况下 我还想指定均值和方差 并从 多 正态分布中提取数据 但最重要的是 我想指定自相关 如何使用 numpy 或 scikit lear
  • 为什么我会收到“构造函数未定义”错误?

    为什么下面的代码会产生编译错误 构造函数AA 未定义 它不应该调用默认构造函数吗 public class A public A public class AA extends A public AA int aa public class
  • IPC::Run - 检测早产儿退出和关闭管道

    我想使用 IPC Run 通过孩子的 STDIN STDOUT 和 STDERR 开始 泵送 完成 与孩子进行通信 似乎有效 我想知道如何检测 儿童过早退出 例如由错误引起 水管被孩子关闭 The pump抛出一个die出现错误时 或将其消
  • 如何在 Python 中从 URL 读取图像数据?

    当我们处理本地文件时 我想做的事情相当简单 但当我尝试使用远程 URL 来执行此操作时 问题就出现了 基本上 我正在尝试从从 URL 提取的文件创建 PIL 图像对象 当然 我总是可以只获取 URL 并将其存储在临时文件中 然后将其打开到图
  • 如何从生产中删除 console.log?

    如何从生产中删除所有 console log 此代码无法运行laravel mix 4 x webpack mix js mix js resources js app js public js if mix inProduction mi
  • android 无法启动模拟器:无法运行程序

    我已经在Ubuntu上成功安装了android SDK和android eclipse插件 一切都工作正常 直到我删除 Ubuntu 并安装 Linux Mint 我再次安装了 SDK 并使用了我在 Ubuntu 上使用的相同 Eclips
  • “未提供任何值的属性”错误 - UrlFetchApp

    我有以下错误 未提供任何值的属性 错误来自行 var content UrlFetchApp fetch url getContentText 这是我的代码 function getArray var newData new Array v
  • 在golang中一起执行bash echo和nc [重复]

    这个问题在这里已经有答案了 这可能是一个简单的问题 在 Linux 机器上工作 我正在尝试从go程序 我有一个服务器正在监听请求 但这行代码给我带来了问题 cmd exec Command echo n hello nc localhost
  • Linux:在 docker 容器中找不到现有共享库

    我尝试在 docker 容器内设置 FastRTPS 我编写了一个 Dockerfile 它从源代码构建 FastRTPS 及其依赖项 并安装库并提供示例 但这些例子不起作用 opt usr local examples C HelloWo
  • 如何设置android wifi热点的高级设置

    我通过以下代码打开便携式 wifi 热点 private void createWifiAccessPoint WifiManager wifiManager WifiManager getBaseContext getSystemServ
  • KQL 正则表达式行提取

    我有一个名为 AdditionalExtensions 的专栏 其中包含以下内容 start Aug 13 2022 20 42 17 logver700060366 ad 我想添加正则表达式搜索以仅提取并显示日期和时间 如下所示 2022
  • Jar 文件名形成 java 代码

    我想从我的 java 代码中确定 jar 文件名 我在谷歌中找到了很多解决方案 但没有任何效果 只是为了看看我在这里尝试了什么 这是一个 stackoverflow 论坛 其中发布了一堆解决方案 堆栈溢出 https stackoverfl
  • UINavigationBar:拦截后退按钮和后退滑动手势

    我有一个 UINavigationBar 可以拦截后退按钮点击 如果有未保存的更改 则会提醒用户 这是基于中提出的解决方案UINavigationController 和 UINavigationBarDelegate ShouldPopI
  • 条目 '' 已添加错误

    我在 ASP net 中有一个 web config 给我配置错误
  • 如何使用 Promise.all 并以对象作为输入

    我一直在开发一个供自己使用的小型 2D 游戏库 但遇到了一些问题 库中有一个名为 loadGame 的特定函数 它将依赖项信息作为输入 资源文件和要执行的脚本列表 这是一个例子 loadGame root source folder for