web-dev-qa-db-fra.com

Déclencher la promesse lorsqu'un événement se déclenche

Tout mon projet utilise des promesses (Bluebird), mais il existe une bibliothèque particulière qui utilise EventEmitter.

Je veux réaliser quelque chose comme:

Promise.on('connect', function() {
    x.doSomething();
}).then(function() {
    return new Promise(function(resolve) {
        y.doAction(resolve); // this will result in `eventB` getting emitted
    });
}).on('eventB', function() {
    z.handleEventB();
}).then(function() {
    z.doSomethingElse();
});

J'ai lu la réponse à EventEmitter au milieu d'une chaîne de promesses . Cela me donne un moyen d'exécuter le rappel pour l'événement "connect". Voici où je suis arrivé jusqu'ici

var p = new Promise(function(resolve) {
    emitter.on('connect', resolve);
});
p.on = function() {
    emitter.on.apply(emitter, arguments);
    return p;
};
p.on('connect', function() {
    x.doSomething();
}).then(function() {
    return new Promise(function(resolve) {
        y.doAction(resolve); // this will result in eventB getting emitted
    });
});

Maintenant, comment enchaîner davantage pour 'eventB'?

17
Jaydeep Solanki

Je suppose que vous voulez faire une chaîne de choses différente pour chaque événement. Même si eventB est déclenché par les actions de connect, vous pouvez le traiter comme un autre flux de logique.

Note latérale: Pour éviter toute confusion pour vous et toute autre personne qui doit lire cette base de code, je vous déconseille de compléter les promesses avec des méthodes supplémentaires, sauf si vous êtes très minutieux à propos de les documenter.

D'après votre exemple, il semble que ce qui suit fonctionnerait.

var Promise = require( 'bluebird' )
var emitter = someEmitter()
var connected = new Promise( function( resolve ){
    emitter.on( 'connect', resolve )
})

var eventBHappened = new Promise( function( resolve ){
    emitter.on( 'eventB', resolve )
})

connected.then( function(){
    return x.doSomething()
}).then( function(){
    return y.doSomethingElse() // will trigger `eventB` eventually
})

// this promise stream will begin once `eventB` has been triggered
eventBHappened.then( function(){ 
    return z.doSomething()
})

Si vous souhaitez simplifier cette constante

var p = new Promise( function( resolve ){
    emitter.on( 'something', resolve )
})

Vous pouvez utiliser quelque chose comme ça

function waitForEvent( emitter, eventType ){
    return new Promise( function( resolve ){
        emitter.on( eventType, resolve )
    })
}

Ce qui transforme la solution de code ci-dessus en

var Promise = require( 'bluebird' )
var emitter = someEmitter()

function waitForEvent( eventEmitter, eventType ){
    return new Promise( function( resolve ){
        eventEmitter.on( eventType, resolve )
    })
}

waitForEvent( emitter, 'connect' ).then( function(){
    return x.doSomething()
}).then( function(){
    return y.doSomethingElse() // will trigger `eventB` eventually
})

// this promise stream will begin once `eventB` has been triggered
waitForEvent( emitter, 'eventB' ).then( function(){ 
    return z.doSomething()
})

Et parce que les fonctions en Javascript capturent la portée où elles ont été définies, ce code pourrait être encore simplifié pour

var Promise = require( 'bluebird' )
var emitter = someEmitter()

function waitForEvent( type ){
    return new Promise( function( resolve ){
        //emitter has been captured from line #2
        emitter.on( type, resolve ) 
    })
}

waitForEvent( 'connect' ).then( function(){
    return x.doSomething()
}).then( function(){
    return y.doSomethingElse() // will trigger `eventB` eventually
})

// this promise stream will begin once `eventB` has been triggered
waitForEvent( 'eventB' ).then( function(){ 
    return z.doSomething()
})
23
JoshWillik

J'ai fait face au même problème et j'ai écrit une minuscule bibliothèque d'encapsulation de promesses ( contrôlée-promesse ) qui permet de promettre des émetteurs d'événements. La solution pour votre exemple est:

const Promise = require('bluebird');
const ControlledPromise = require('controlled-promise');

const emitter = someEmitter();
const waiting = new ControlledPromise();

function waitForEvent(type) {
    return waiting.call(() => {
       emitter.once(type, event => waiting.resolve(event));
    });
}

waitForEvent('connect')
    .then(() => x.doSomething())
    .then(() => waitForEvent('eventB'))
    .then(() => z.doSomethingElse());

Les avantages d'une telle approche:

  • retour automatique de la promesse existante pendant qu'elle est en attente
  • accès facile à resolve()/reject() rappels
1
vitalets