首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将对象作为输入使用Promise.all

如何将对象作为输入使用Promise.all
EN

Stack Overflow用户
提问于 2015-03-27 11:44:46
回答 16查看 46.3K关注 0票数 35

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

代码语言:javascript
运行
复制
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函数将资源转换为promises对象。

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

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

下面是loadGame的代码:

代码语言:javascript
运行
复制
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);
        });
    });
};

理想情况下,我希望以某种方式正确地管理资源的承诺列表,同时仍然为每个项目管理一个标识符。任何帮助都会很感谢,谢谢。

EN

Stack Overflow用户

发布于 2015-03-28 12:09:38

编辑:这个问题最近似乎得到了一些关注,所以我想我应该把我目前的解决方案添加到这个问题上,我现在正在几个项目中使用这个解决方案。这是一个比我两年前写的答案底部的代码更好的lot

新的loadAll函数假设其输入是将资产名称映射到promises的对象,并且它还利用了实验函数Object.entries,该函数并不是在所有环境中都可用。

代码语言:javascript
运行
复制
// fromEntries :: [[a, b]] -> {a: b}
// Does the reverse of Object.entries.
const fromEntries = list => {
    const result = {};

    for (let [key, value] of list) {
        result[key] = value;
    }

    return result;
};

// addAsset :: (k, Promise a) -> Promise (k, a)
const addAsset = ([name, assetPromise]) =>
    assetPromise.then(asset => [name, asset]);

// loadAll :: {k: Promise a} -> Promise {k: a}
const loadAll = assets =>
    Promise.all(Object.entries(assets).map(addAsset)).then(fromEntries);

因此,我根据Bergi的回答提出了适当的代码。如果其他人也有同样的问题,这里就是。

代码语言:javascript
运行
复制
// maps an object and returns an array
var mapObjectToArray = function (obj, action) {
    var res = [];

    for (var key in obj) res.push(action(obj[key], key));

    return res;
};

// converts arrays back to objects
var backToObject = function (array) {
    var object = {};

    for (var i = 0; i < array.length; i ++) {
        object[array[i].name] = array[i].val;
    }

    return object;
};

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

        // get resources
        var types = {
            jpg : getImage,
            png : getImage,
            bmp : getImage,

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

            json : getJSON
        };

        // wait for all resources to load
        Promise.all(mapObjectToArray(game.resources, function (path, name) {
            // get file extension
            var extension = path.match(/(?:\.([^.]+))?$/)[1];

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

            // reject if there wasn't one
            if (!get) return reject(Error('Unknown resource type "' + extension + '".'));

            // get it and convert to 'object-able'
            return get(root + path, name).then(function (resource) {
                return {val : resource, name : name};
            });

            // someday I'll be able to do this
            // return get(root + path, name).then(resource => ({val : resource, name : name}));
        })).then(function (resources) {
            // convert resources to object
            resources = backToObject(resources);

            // attach resources to window
            window.resources = resources;

            // sequentially load scripts
            return game.scripts.reduce(function (queue, path) {
                return queue.then(function () {
                    return getScript(root + path);
                });
            }, Promise.resolve()).then(function () {
                // resources is final value of the whole promise
                fulfill(resources);
            });
        });
    });
};
票数 2
EN
查看全部 16 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29292921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档