javascript – 如何将Promise.all与对象一起用作输入

我一直在为我自己使用的小型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函数将资源转换为promises对象.

问题是它试图使用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构造函数,this usage is an antipattern

现在,针对您的实际问题:正确识别后,您错过了每个值的关键字.您需要在每个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.

此外,您不应该使用该伪递归加载函数.您可以简单地将承诺链接在一起:

….then(function (resources) {
    return game.scripts.reduce(function(queue, script) {
        return queue.then(function() {
            return getScript(root + script);
        });
    }, Promise.resolve()).then(function() {
        return resources;
    });
});

相关文章

最后的控制台返回空数组.控制台在ids.map函数完成之前运行va...
我正在尝试将rxJava与我已经知道的内容联系起来,特别是来自J...
config.jsconstconfig={base_url_api:"https://douban....
我正在阅读MDN中的javascript,并且遇到了这个谈论承诺并且不...
config.jsconstconfig={base_url_api:"https://douban....
这是我的代码main.cpp:#include<string>#include<...