Wie zu verwenden Versprechen.alle mit einem Objekt als Eingabe
Habe ich gearbeitet, auf einem kleinen 2D-Spiel Bibliothek für meinen eigenen Gebrauch, und ich habe in ein bisschen ein problem. Gibt es eine Besondere Funktion in der Bibliothek, genannt loadGame, nimmt die Abhängigkeit als info-input (Ressourcen-Dateien, und eine Liste der Skripts ot ausgeführt werden). Hier ist ein Beispiel.
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"
]
})
Jedes Element in resources, hat einen Schlüssel, der verwendet wird, durch den das Spiel Zugriff auf die jeweilige Ressource. Die loadGame-Funktion wandelt die Ressourcen in ein Objekt Versprechen.
Das problem ist, dass es versucht, zu verwenden Verspricht.alle zu überprüfen, denn wenn Sie sind alle bereit, aber Versprechen.alle akzeptiert nur iterables als Eingänge, so dass ein Objekt wie das, was ich habe, ist aus der Frage.
So, ich habe versucht, zu konvertieren das Objekt in ein array, das funktioniert gut, außer jede Ressource ist nur ein element in einem array und nicht über eine Taste, Sie zu identifizieren.
Hier ist der code für 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);
});
});
};
Idealerweise würde ich gerne für einige Weg, um richtig zu verwalten eine Liste von Versprechungen für die Ressourcen, während immer noch mantaining einen Bezeichner für jedes Element. Jede Hilfe würde geschätzt, danke.
InformationsquelleAutor der Frage Matt | 2015-03-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erstens: der Schrott, der
Promise
Konstruktor, diese Nutzung ist ein antipattern!Nun zu deinem eigentlichen problem: Wie du richtig erkannt hast, fehlt der Schlüssel für jeden Wert. Sie müssen, um es zu übergeben, die innerhalb jedes Versprechen, so dass Sie zu rekonstruieren, das Objekt, nachdem er erwartete Elemente:
Mächtiger Bibliotheken wie Bluebird, werden auch diese als Helfer-Funktion, wie
Versprechen.props
.Auch, sollten Sie nicht verwenden, die pseudo-rekursive
load
Funktion. Sie können einfach die Kette verspricht zusammen:InformationsquelleAutor der Antwort Bergi
Hier ist eine einfache ES2015 Funktion, die nimmt ein Objekt mit Eigenschaften, die möglicherweise sein Versprechen und gibt ein Versprechen, das Objekt mit aufgelösten Eigenschaften.
Verwendung:
Beachten Sie, dass @Bergi Antwort zurück ein neues Objekt, nicht mutieren, das ursprüngliche Objekt. Wenn Sie wollen, ein neues Objekt, ändern Sie einfach die Initialisierung Wert, der übergeben wird in der senken-Funktion
{}
InformationsquelleAutor der Antwort Zak Henry
Verwendung von async/await und lodash:
InformationsquelleAutor der Antwort Congelli501
Wenn Sie lodash Bibliothek, Sie können dies erreichen, indem ein one-liner Funktion:
InformationsquelleAutor der Antwort david.sevcik
Fehlt
Promise.obj()
MethodeEine kürzere Lösung mit vanilla JavaScript, keine Bibliotheken, keine Schleifen, keine mutation
Hier ist eine kürzere Lösung als die anderen Antworten, mit Hilfe moderner JavaScript-syntax.
Dies schafft eine fehlende
Promise.obj()
Methode, die funktioniert wiePromise.all()
aber für Objekte:Beachten Sie, dass die oben genannten änderungen der globalen
Promise
Objekt, so ist es besser, die Letzte Zeile geändert werden:InformationsquelleAutor der Antwort rsp
Ich tatsächlich erstellt eine Bibliothek, die nur für das und veröffentlicht es auf github und npm:
https://github.com/marcelowa/promise-all-properties
https://www.npmjs.com/package/promise-all-properties
Die einzige Sache ist, dass Sie brauchen, um das zuweisen einer Eigenschaft-name für jedes Versprechen, das Objekt...
hier ein Beispiel aus der README
InformationsquelleAutor der Antwort Marcelo Waisman