Question

Ma question concerne l'élégante parallélisation des promesses dans Oiseau bleu lorsque vous devez transmettre à la fois le contexte et l'argument aux fonctions qui construisent les promesses.

Pour rendre mon problème compréhensible et testable, j'ai fait un exemple sans dépendance.

Supposons que je fasse un calcul ( 1/(xXx) + 1/(x*x) ) impliquant un "ordinateur" asynchrone (dont les ressources doivent être libérées).Le carré et le cube sont calculés de manière asynchrone et indépendante.

Je peux faire mon calcul comme ceci :

InitComputer(2) // returns a promise
.then(invert)
.then(function(arg){
    return Promise.all([
        proto.square(arg),
        proto.cube(arg)
    ]);
}).spread(function(sq, cu){
    this.set(sq + cu);
}).catch(function(err){
    console.log('err:', err);
}).finally(endComputer);

Mais je trouve cet usage de all trop lourd par rapport à ce qui est théoriquement possible.Lorsque vous passez une fonction en argument à then, c'est exécuté.Lorsque vous transmettez des fonctions à all, ce n'est pas le cas, il y a une erreur.Je soupçonne qu'il me manque un utilitaire ou un modèle...

Existe-t-il une solution pour le changer en quelque chose de plus simple dans ce style :

InitComputer(2)
.then(invert)
.all([
    proto.square,
    proto.cube
]).spread(function(sq, cu){
    this.set(sq + cu);
}).catch(function(err){
    console.log('err:', err);
}).finally(endComputer);

?

Je pourrais probablement pirater Promesse.prototype.all ou définir une nouvelle fonction pour éviter d'augmenter le polymorphisme mais je ne m'intéresse qu'aux solutions n'impliquant pas la modification d'objets que je ne possède pas.


Annexe:

Voici comment est défini "l'ordinateur" pour mon test :

var Promise = require("bluebird");

function Computer(){}
function InitComputer(v){
    // initializing a computer is asynchronous and may fail hence the promise
    var c = new Computer(), resolver = Promise.defer();
    setTimeout(function(){
        if (v>1) resolver.resolve(v);
        else resolver.reject(new Error("bad value: "+v));
    },100);
    return resolver.promise.bind(c);
}
var proto = Computer.prototype;
proto.square = function(x){
    // imagine this really uses the computer and is asynchronous
    if (!this instanceof Computer) throw new Error('not a computer');
    return x*x
}
proto.cube = function(x){ return x*x*x }
proto.set = function(v){ this.value = v }

function endComputer(){
    // releases resources here
    console.log('value:', this.value);
}

// this asynchronous function doesn't involve or know the computer
function invert(v){ return 1/v }
Était-ce utile?

La solution

Vous n'êtes pas obligé d'utiliser Promise.all là.Au lieu de faire :

.then(function(arg){
    return Promise.all([
        proto.square(arg),
        proto.cube(arg)
    ]);
}).spread(...

Vous pouvez simplement utiliser :

.then(function(arg){
    return [proto.square(arg), proto.cube(arg)];
}).spread(...

Si nous avions des fonctions fléchées dans node.js, ce serait aussi simple que :

.then(arg => [proto.square(arg), proto.cube(arg)]).spread(...

Promise.all doit être utilisé lorsque vous en avez besoin commencer une chaîne de promesses avec au moins 2 promesses.Par exemple:

var promise1 = somePromise();
var promise2 = somePromise2();

// Start the chain here
Promise.all([promise1, promise2])
.spread(function(value1, value2) {
    // ...
});

Autres conseils

Pour le cas d'utilisation de la gestion des ressources comme vous le mentionnez, bluebird a Promise.using(). Promise.using() vous permet de configurer disposer() fonction pour fermer automatiquement la ressource récupérée de manière asynchrone lorsque vous avez fini d'utiliser

Promise.join() aiderait également à combiner les résultats de cube et square méthodes asynchrones

Ici, j'ai légèrement réécrit votre InitComputer exemple pour illustrer comment cela fonctionne - il renvoie maintenant le Computer exemple avec val ajouté comme propriété, au lieu du val, et j'ai placé endComputer sur le proto également

note:tu peux toujours utiliser Promise.method() comme ça au lieu de renvoyer un différé :

var invert = Promise.method(function invert(v){ return 1/v })

nouvel ordinateur d'initialisation :

function InitComputer(v){
    var c = new Computer(), resolver = Promise.defer();
    setTimeout(function(){
        if (v>1) {
            c.val = v;
            resolver.resolve(c);
        }
        else resolver.reject(new Error("bad value: "+v));
    },100); /** notice resource disposer function added below **/
    return resolver.promise.bind(c).disposer(function(compu){compu.endComputer()});
}

nouveau code :

Promise.using(InitComputer(1.2), function(computer){
    return invert(computer.val)
    .then(function(inverted){
        return Promise.join(computer.square(inverted), computer.cube(inverted), 
            function(sq, cu){
                computer.set(sq + cu)
            }
        )
    })
    .catch(function(err){
        console.log('err:', err);
    });
})
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top