-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
94 lines (90 loc) · 2.86 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
'use strict';
/**
* @typedef {Object} PromisifyOptions
* @property {string} name Name of the event.
* @property {!boolean function(data: *)} filter [description]
* @property {boolean} aggregate If set, it will aggregate the data from the specified event.
* @property {string} errorName The event to be used to abort/reject the promise in addition to error.
* @property {boolean} [ignoreErrors=false] Should the default error handler be ignored.
*/
/**
* @typedef {Object} PromisifyResult
* @property {*} value The value from the final event emitted.
* @property {*[]} aggregated The aggregated data.
*/
/**
* Wraps an EventEmitter for promise support.
* Once the expected event is called, the promise will be resolved with the emitted value.
* If the error event is emitted before that, the promise will be rejected with the given error.
* @param {EventEmitter} obj The emitter to bind on
* @param {string|PromisifyOptions} name The event name or an advanced options object.
* @return {Promise<*|PromisifyResult>} Promise
*/
const nativePromise = Promise;
module.exports = Promise => function promisifyEvent(obj, nameOrOptions) {
Promise = Promise || nativePromise;
const filter = nameOrOptions.filter || false;
const aggregateEventName = nameOrOptions.aggregate;
const eventName = typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions.name;
const errorEvent = nameOrOptions.errorName;
const ignoreErrors = nameOrOptions.ignoreErrors;
let aggregated;
let aggregateEventHandle;
if (aggregateEventName) {
aggregated = [];
aggregateEventHandle = data => {
aggregated.push(data);
};
obj.on(aggregateEventName, aggregateEventHandle);
}
return new Promise((resolve, reject) => {
const succHandler = data => {
if (filter && !filter(data)) {
return;
}
obj.removeListener('error', errorHandler);
if (aggregateEventName) {
obj.removeListener(aggregateEventName, aggregateEventHandle);
return resolve({
value: data,
aggregated: aggregated
});
}
return resolve(data);
};
const errorHandler = error => {
if (!(error instanceof Error)) {
if (typeof error === 'string') {
error = new Error(error);
} else {
const tempError = new Error('Error event emitted, event contained in .event');
tempError.event = error;
error = tempError;
}
}
if (aggregateEventName) {
obj.removeListener(aggregateEventName, aggregateEventHandle);
}
obj.removeListener(eventName, succHandler);
obj.removeListener('error', errorHandler);
if (errorEvent) {
obj.removeListener(errorEvent, errorHandler);
}
reject(error);
};
if (filter) {
obj.on(eventName, succHandler);
} else {
obj.once(eventName, succHandler);
}
obj.once('error', error => {
if (ignoreErrors) {
return;
}
errorHandler(error);
});
if (errorEvent) {
obj.once(errorEvent, errorHandler);
}
});
};