J'ai une situation où il serait très pratique d'utiliser Promise.all comme tel Promise.all({}) au lieu du Promise.all ([]) plus standard.

Mais cela ne semble pas fonctionner

Promise.all({a:1,b:2}).then(function(val){
   console.log('val:',val);
});

Alors que cela fait bien sûr

Promise.all([1,2,3]).then(function(val){
   console.log('val:',val);
});

(ce à quoi je m'attendrais serait que Promise.all mappe les valeurs du littéral Object, mais laisse les clés intactes.)

Mais les documents MDN pour Promise semblent pour indiquer que Promise all fonctionnera pour tout itérable. À ma connaissance, un objet littéral {} est un itérable. Alors qu'est-ce qui me manque?

8
Alexander Mills 7 mars 2016 à 03:55

8 réponses

Meilleure réponse

L'objet n'a pas de symbole Iterator si vous regardez le mdn documentation pour ceux-ci.

Ce que vous pouvez faire, c'est utiliser une fonction d'outil pour créer un objet itérable et le consommer plus tard.

référence à la source objectEntries, mais nodejs n'implémente pas Reflect, donc pour le but de l'utiliser avec le noeud je le change juste en utilisant Object.keys ()

function objectEntries(obj) {
    let index = 0;

    // In ES6, you can use strings or symbols as property keys,
    // Reflect.ownKeys() retrieves both
    let propKeys = Object.keys(obj);

    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            if (index < propKeys.length) {
                let key = propKeys[index];
                index++;
                return { value: [key, obj[key]] };
            } else {
                return { done: true };
            }
        }
    };
}
3
Dmitry Matveev 7 mars 2016 à 01:38

Utilisez Object.values. Fonctionne dans Firefox Nightly:

Promise.all(Object.values({a:1,b:2}))
.then(vals => console.log('vals: ' + vals)) // vals: 1,2
.catch(e => console.log(e));

var console = { log: msg => div.innerHTML += msg + "<br>" };
<div id="div"></div>

Ensuite, pour remettre les résultats dans un objet, nous pouvons créer une fonction Promise.allParams:

Promise.allParams = o => 
  Promise.all(Object.values(o)).then(promises =>
    Object.keys(o).reduce((o2, key, i) => (o2[key] = promises[i], o2), {}));

// Demo:

Promise.allParams({a:1,b:2}).then(function(val){
   console.log('val: ' + JSON.stringify(val)); // val: {"a":1,"b":2}
});

var console = { log: msg => div.innerHTML += msg + "<br>" };
<div id="div"></div>
3
jib 7 mars 2016 à 06:52

Voici une autre solution asynchrone / attendent ES6:

async function allOf(hash = {}) {
  const promises = Object.keys(hash).map(async key => ({[key]: await hash[key]}));
  const resolved = await Promise.all(promises);
  return resolved.reduce((hash, part) => ({...hash, ...part}), {});
}

Cela convertit les clés en une promesse qui produit un hachage d'un seul élément. Ensuite, à la fin, nous combinons tous les hachages du tableau en un seul hachage. Vous pouvez même le compacter en un seul revêtement, au détriment de la lisibilité.

async function allOfOneLiner(hash = {}) {
  return (await Promise.all(Object.keys(hash).map(async k => ({[k]: await hash[k]})))).reduce((h, p) => ({...h, ...p}), {});
}
3
Staale 19 sept. 2018 à 18:04

Tous les objets ne sont pas itérables par défaut. Vous pouvez rendre un objet itérable en définissant une méthode @@iterator. @@iterator est un Symbole bien connu disponible en tant que Symbol.iterator:

  • Nom de spécification
    @@ itérateur
  • [[Description]]
    "Symbol.iterator"
  • Valeur et objectif
    Une méthode qui renvoie l'itérateur par défaut d'un objet. Appelé par la sémantique de l'instruction for-of.

Par exemple, cela rendra tous les objets itérables (probablement pas une bonne idée):

Object.prototype[Symbol.iterator] = function*() {
  for(let key of Object.keys(this))
    yield this[key];
};

Ensuite, vous pourrez utiliser

Promise.all({a:1,b:2}).then(function(val){
   console.log('val:', val); // [ 1, 2 ]
});
0
Oriol 7 mars 2016 à 02:28

Avec Babel / ES2015, vous pouvez utiliser Object.keys et map pour obtenir les valeurs comme ceci:

const obj = {a:1,b:2};                                                                                                                               
const vals = Object.keys(obj).map(k=>obj[k]);                                                                                                        
Promise.all(vals).then( vals => { console.log('vals', vals) });                         
0
Jason Livesay 7 mars 2016 à 04:10
Syntax
Promise.all(iterable);
Parameters

itérable

Un objet itérable, tel qu'un tableau. Voir itérable.

1
BlackMamba 7 mars 2016 à 01:17

Cette fonction fait l'affaire:

Promise.allAssoc = function(object){
    var values = [], keys = [];
    for(var key in object){
        values.push(object[key]);
        keys.push(key);
    }
    return Promise.all(values).then(function(results){
        var out = {};
        for(var i=0; i<results.length; i++) out[keys[i]] = results[i];
        return out;
    });
};
0
chrmcpn 11 juil. 2017 à 20:01

Manière ES6

Promise.hashProperties = async function(object) {
    const keys = [];
    const values = [];

    for (const key in object) {
        keys.push(key);
        values.push(object[key]);
    }

    const results = await Promise.all(values);

    for (var i=0; i<results.length; i++)
        object[keys[i]] = results[i];

    return object;
};
0
ElSajko 6 sept. 2018 à 08:37