p-event
Advanced tools
Comparing version 2.1.0 to 2.2.0
63
index.js
@@ -20,18 +20,19 @@ 'use strict'; | ||
module.exports = (emitter, event, options) => { | ||
const multiple = (emitter, event, options) => { | ||
let cancel; | ||
const ret = new Promise((resolve, reject) => { | ||
if (typeof options === 'function') { | ||
options = {filter: options}; | ||
} | ||
options = Object.assign({ | ||
rejectionEvents: ['error'], | ||
multiArgs: false | ||
multiArgs: false, | ||
resolveImmediately: false | ||
}, options); | ||
if (!(options.count >= 0 && (options.count === Infinity || Number.isInteger(options.count)))) { | ||
throw new TypeError('The `count` option should be at least 0 or more'); | ||
} | ||
const items = []; | ||
const {addListener, removeListener} = normalizeEmitter(emitter); | ||
const resolveHandler = (...args) => { | ||
const onItem = (...args) => { | ||
const value = options.multiArgs ? args : args[0]; | ||
@@ -43,13 +44,17 @@ | ||
cancel(); | ||
resolve(value); | ||
items.push(value); | ||
if (options.count === items.length) { | ||
cancel(); | ||
resolve(items); | ||
} | ||
}; | ||
const rejectHandler = (...args) => { | ||
const rejectHandler = error => { | ||
cancel(); | ||
reject(options.multiArgs ? args : args[0]); | ||
reject(error); | ||
}; | ||
cancel = () => { | ||
removeListener(event, resolveHandler); | ||
removeListener(event, onItem); | ||
@@ -61,3 +66,3 @@ for (const rejectionEvent of options.rejectionEvents) { | ||
addListener(event, resolveHandler); | ||
addListener(event, onItem); | ||
@@ -67,2 +72,6 @@ for (const rejectionEvent of options.rejectionEvents) { | ||
} | ||
if (options.resolveImmediately) { | ||
resolve(items); | ||
} | ||
}); | ||
@@ -80,2 +89,23 @@ | ||
}; | ||
module.exports = (emitter, event, options) => { | ||
if (typeof options === 'function') { | ||
options = {filter: options}; | ||
} | ||
options = Object.assign({}, options, { | ||
count: 1, | ||
resolveImmediately: false | ||
}); | ||
const arrayPromise = multiple(emitter, event, options); | ||
const promise = arrayPromise.then(array => array[0]); | ||
promise.cancel = arrayPromise.cancel; | ||
return promise; | ||
}; | ||
module.exports.multiple = multiple; | ||
module.exports.iterator = (emitter, event, options) => { | ||
@@ -116,3 +146,2 @@ if (typeof options === 'function') { | ||
for (const rejectionEvent of options.rejectionEvents) { | ||
// eslint-disable-next-line no-use-before-define | ||
removeListener(rejectionEvent, rejectHandler); | ||
@@ -122,3 +151,2 @@ } | ||
for (const resolutionEvent of options.resolutionEvents) { | ||
// eslint-disable-next-line no-use-before-define | ||
removeListener(resolutionEvent, resolveHandler); | ||
@@ -182,2 +210,3 @@ } | ||
} | ||
if (hasPendingError) { | ||
@@ -187,5 +216,7 @@ hasPendingError = false; | ||
} | ||
if (done) { | ||
return Promise.resolve({done: true, value: undefined}); | ||
} | ||
return new Promise((resolve, reject) => nextQueue.push({resolve, reject})); | ||
@@ -192,0 +223,0 @@ }, |
{ | ||
"name": "p-event", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"description": "Promisify an event by waiting for it to be emitted", | ||
@@ -48,6 +48,6 @@ "license": "MIT", | ||
"devDependencies": { | ||
"ava": "*", | ||
"delay": "^3.0.0", | ||
"xo": "*" | ||
"ava": "^1.1.0", | ||
"delay": "^4.1.0", | ||
"xo": "^0.24.0" | ||
} | ||
} |
@@ -29,3 +29,3 @@ # p-event [![Build Status](https://travis-ci.org/sindresorhus/p-event.svg?branch=master)](https://travis-ci.org/sindresorhus/p-event) | ||
try { | ||
await pEvent(emitter, 'finish'); | ||
const result = await pEvent(emitter, 'finish'); | ||
@@ -148,2 +148,58 @@ // `emitter` emitted a `finish` event | ||
### pEvent.multiple(emitter, event, options) | ||
Wait for multiple event emissions. Returns an array. | ||
This method has the same arguments and options as `pEvent()` with the addition of the following options: | ||
#### options | ||
Type: `Object` | ||
##### count | ||
*Required*<br> | ||
Type: `number` | ||
The number of times the event needs to be emitted before the promise resolves. | ||
##### resolveImmediately | ||
Type: `boolean`<br> | ||
Default: `false` | ||
Whether to resolve the promise immediately. Emitting one of the `rejectionEvents` won't throw an error. | ||
**Note**: The returned array will be mutated when an event is emitted. | ||
Example: | ||
```js | ||
const emitter = new EventEmitter(); | ||
const promise = pEvent.multiple(emitter, 'hello', { | ||
resolveImmediately: true, | ||
count: Infinity | ||
}); | ||
const result = await promise; | ||
console.log(result); | ||
//=> [] | ||
emitter.emit('hello', 'Jack'); | ||
console.log(result); | ||
//=> ['Jack'] | ||
emitter.emit('hello', 'Mark'); | ||
console.log(result); | ||
//=> ['Jack', 'Mark'] | ||
// Stops listening | ||
emitter.emit('error', new Error('😿')); | ||
emitter.emit('hello', 'John'); | ||
console.log(result); | ||
//=> ['Jack', 'Mark'] | ||
``` | ||
### pEvent.iterator(emitter, event, [options]) | ||
@@ -214,2 +270,31 @@ ### pEvent.iterator(emitter, event, filter) | ||
## Tip | ||
### Dealing with calls that resolve with an error code | ||
Some functions might use a single event for success and for certain errors. Promises make it easy to have combined error handler for both error events and successes containing values which represent errors. | ||
```js | ||
const pEvent = require('p-event'); | ||
const emitter = require('./some-event-emitter'); | ||
(async () => { | ||
try { | ||
const result = await pEvent(emitter, 'finish'); | ||
if (result === 'unwanted result') { | ||
throw new Error('Emitter finished with an error'); | ||
} | ||
// `emitter` emitted a `finish` event with an acceptable value | ||
console.log(result); | ||
} catch (error) { | ||
// `emitter` emitted an `error` event or | ||
// emitted a `finish` with 'unwanted result' | ||
console.error(error); | ||
} | ||
})(); | ||
``` | ||
## Related | ||
@@ -216,0 +301,0 @@ |
13913
169
307