JavaScript
Node.js
promise
reactjs
babel

EventEmitterをPromiseに対応させる

More than 1 year has passed since last update.

react-router@1.0.0-rc3を使っていると、onEnterでStoreを更新して、終わってからRouteへ移動したい。Angularで言うui-routerのresolveが欲しいと思っていました。

EventEmitterを継承して.emitをオーバーライドすれば対応可能です。軽くテストを通したライブラリも公開しています1

具体的には下記のように実装します。


async-emitter.js

// Dependencies

import {EventEmitter} from 'events'

// Public
class AsyncEmitter extends EventEmitter{
emit(event,...args){
let promises= []

this.listeners(event).forEach(listener=>{
promises.push(listener(...args))
})

return Promise.all(promises)
}
}

export default AsyncEmitter


最後にPromise.allで結果を梱包するので、配列の結果か、最初のエラーを補足します。


async-emitter-test.js

import AsyncEmitter from './async-emitter'

let emitter= new AsyncEmitter

// Add event listeners
emitter.on('foo',(arg1)=>{
return new Promise((resolve,reject)=>{
if(arg1==null){
resolve('bar')
}
else{
reject(new Error('beep'))
}
})
})

// Dispatch the `foo` event
emitter.emit('foo')
.then(values=>{
console.log(values[0] === 'bar') // true

// expect to be rejected
return emitter.emit('foo','kaboom')
})
.catch(reason=>{
console.error(reason.message === 'beep') // true
})


babel-node async-emitter-test.js

true
true

react-router@1.0.0-rc3では、onEnterの第三引数にcallbackを受けますので、上手く活用出来ると思います。





  1. v0.4.0から、.emit.emitParallelにメソッド名を変更しました。