web-dev-qa-db-ja.com

イベントが発生したときにPromiseをトリガーする

プロジェクト全体で(Bluebird)Promiseを使用していますが、EventEmitterを使用する特定のライブラリが1つあります。

私は次のようなことを達成したいです:

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();
});

私は Promiseのチェーンの真ん中にあるEventEmitter に対する答えを読みました。これにより、「接続」イベントのコールバックを実行する方法が得られます。これが私がこれまでに得た場所です

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
    });
});

次に、「eventB」にさらにチェーンする方法は?

17
Jaydeep Solanki

イベントごとに異なる一連の処理を実行したいと思います。 eventBconnectのアクションによってトリガーされたとしても、それを別のロジックストリームのように扱うことができます。

サイドノート:あなたとこのコードベースを読む必要がある他の人の混乱を避けるために、あなたがveryでない限り、追加のメソッドでpromiseを補足しないことをお勧めしますそれらを文書化します。

あなたの例から、次のように機能するようです。

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()
})

この定数を単純化したい場合

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

あなたはこのようなものを使うことができます

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

上記のコードソリューションを

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()
})

また、JavaScriptの関数はそれらが定義されたスコープをキャプチャするため、このコードをさらに簡略化して

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

私は同じ問題に直面し、イベントエミッターを約束することを可能にする小さな約束ラッピングライブラリ( 制御された約束 )を書きました。あなたの例の解決策は:

_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());
_

そのようなアプローチの利点:

  • 保留中の既存のプロミスの自動復帰
  • resolve()/reject()コールバックへの簡単なアクセス
1
vitalets