Last active
April 15, 2018 20:24
-
-
Save fijiwebdesign/3b7ffeea0734dc3314bcbe9fdd6b543f to your computer and use it in GitHub Desktop.
Emit promises in place of events
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { EventEmitter } = require('events'); | |
const PromiseEmitter = require('../PromiseEmitter'); | |
const eventEmitter = new EventEmitter(); | |
const promiseEmitter = new PromiseEmitter(eventEmitter); | |
// simulate events | |
setTimeout(() => eventEmitter.emit('foo', { name: 'foo', age: 'unknown' })); | |
setTimeout(() => eventEmitter.emit('bar', { name: 'bar', age: '5 ses' }), 5000); | |
promiseEmitter | |
.on('foo') | |
.timeout(1000) // timeout after 1 sec | |
.then(foo => console.log('foo event', foo)) | |
.catch(err => console.log('foo event error', err)); | |
promiseEmitter | |
.on('bar') | |
.timeout(1000) // timeout after 1 sec | |
.then(foo => console.log('bar event', foo)) | |
.catch(err => console.log('bar event error', err)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Emit a promise once in place of event with timeout | |
* @param {EventEmitter} emitter | |
*/ | |
function PromiseEmitter(emitter) { | |
this.emitter = emitter; | |
} | |
PromiseEmitter.prototype.once = function once(event) { | |
let timer; | |
const promise = new Promise(resolve => { | |
this.emitter.once(event, (...args) => { | |
resolve.apply(this.emitter, args); | |
}); | |
}); | |
promise.timeout = timeout => { | |
const timeoutErr = new Error('Timeout'); | |
clearTimeout(timer); | |
return new Promise((resolve, reject) => { | |
setTimeout(() => reject.call(this.emitter, timeoutErr), timeout); | |
promise.then((...args) => resolve.apply(this.emitter, args)); | |
}); | |
}; | |
return promise; | |
}; | |
PromiseEmitter.prototype.on = PromiseEmitter.prototype.once; | |
module.exports = PromiseEmitter; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { EventEmitter } = require('events'); | |
const PromiseEmitter = require('../lib/PromiseEmitter'); | |
// const io = require('socket.io/client'); | |
// const socket = io.connect('http://localhost'); // socket is an EventEmitter | |
const socket = new EventEmitter(); // mock socket.io | |
socket.promise = new PromiseEmitter(socket); // wrap on(event) with promise | |
// emulate socket.io | |
setImmediate(() => socket.emit('connected')); | |
function onceLoggedIn(status) { | |
console.log('auth status', status); | |
} | |
function onceLoginError(err) { | |
console.log('auth err', err); | |
} | |
function showRooms(rooms) { | |
console.log('rooms', rooms); | |
} | |
function showRoomUsers({ room, users }) { | |
console.log('show room %o users %o ', room, users); | |
} | |
// mix events and promises to for async, parallel, sync, sequential flow control | |
socket.on('connected', () => { | |
setImmediate(() => socket.emit('auth', { username: 'foo', password: 'bar' })); | |
socket.promise | |
.once('auth') | |
.timeout(1000) // timeout after 1 sec | |
.then(status => onceLoggedIn(status)) | |
.then(() => { | |
setImmediate(() => socket.emit('rooms/list', [{ id: 1 }, { id: 2 }])); // get rooms list | |
return socket.promise.once('rooms/list'); | |
}) | |
.then(rooms => { | |
// generate an async event for each room | |
showRooms(rooms); | |
return rooms.map(room => { | |
const emitter = new EventEmitter(); | |
setTimeout(() => emitter.emit('click', room), Math.random() * 10000); // simulate UI room click | |
return emitter; | |
}); | |
}) | |
.then(emitters => { | |
// many async events into one promise | |
const promises = emitters.map(emitter => new PromiseEmitter(emitter).once('click')); | |
const users = [{ name: 'joe' }, { name: 'jane' }]; | |
return Promise.race(promises).then(room => { | |
console.log('Emitted click on', room); | |
setImmediate(() => socket.emit('room/users', users)); // get users in room | |
return socket.promise | |
.once('room/users') | |
.then(roomUsers => Promise.resolve({ users: roomUsers, room })); | |
}); | |
}) | |
.then(room => { | |
showRoomUsers(room); | |
}) | |
.catch(err => onceLoginError(err)); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment