如何使用 Promise.all 将对象作为输入 [英] How to use Promise.all with an object as input

查看:13
本文介绍了如何使用 Promise.all 将对象作为输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been working on a small 2D game library for my own use, and I've run into a bit of a problem. There is a particular function in the library called loadGame that takes dependency info as input (resource files, and a list of scripts ot be executed). Here's an example.

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 对象.

Each item in resources has a key that is used by the game to access that particular resource. The loadGame function converts the resources into an object of promises.

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

The problem is that it tries to use Promises.all to check for when they're all ready, but Promise.all accepts only iterables as inputs - so an object like what I have is out of the question.

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

So I tried to convert the object into an array, this works great, except each resource is just an element in an array and doesn't have a key to identify them.

这是 loadGame 的代码:

Here's the code for 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);
        });
    });
};

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

Ideally I'd like for some way to properly manage a list of promises for resources while still mantaining an identifier for each item. Any help would be appreciated, thanks.

推荐答案

如果使用 lodash 库,可以实现这是一个单行函数:

If you use lodash library, you can achieve this by a one-liner function:

Promise.allValues = async (object) => {
  return _.zipObject(_.keys(object), await Promise.all(_.values(object)))
}

这篇关于如何使用 Promise.all 将对象作为输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆