mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
cb6cbd12f8
Summary: Deprecates `EventEmitter#removeSubscription`. This required temporarily introducing a new `__removeSubscription` method that is only invoked by `EmitterSubscription`. This is necessary so that we do not completely break usages of `EventEmitter` that are supplying constructor arguments (which is also deprecated, but still supported until the next release). Calling this method will now cause a warning to appear with instructions to instead invoke `remove()` on the subscription itself. Lastly, changed `console.error` deprecation notice to instead use `console.warn`. This is in line with the principle that errors are "broken today" and warnings will be "broken tomorrow". Changelog: [General][Deprecated] - `EventEmitter#removeSubscription` is now deprecated. Reviewed By: rubennorte Differential Revision: D27704279 fbshipit-source-id: 581f5b2ab46b1bcfc1d20898b3d3392988dccbd5
184 lines
6.3 KiB
JavaScript
184 lines
6.3 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @format
|
|
* @flow strict
|
|
* @typecheck
|
|
*/
|
|
|
|
const invariant = require('invariant');
|
|
|
|
import EmitterSubscription from './_EmitterSubscription';
|
|
import {type EventSubscription} from './EventSubscription';
|
|
import EventSubscriptionVendor from './_EventSubscriptionVendor';
|
|
|
|
const sparseFilterPredicate = () => true;
|
|
|
|
/**
|
|
* @class EventEmitter
|
|
* @description
|
|
* An EventEmitter is responsible for managing a set of listeners and publishing
|
|
* events to them when it is told that such events happened. In addition to the
|
|
* data for the given event it also sends a event control object which allows
|
|
* the listeners/handlers to prevent the default behavior of the given event.
|
|
*
|
|
* The emitter is designed to be generic enough to support all the different
|
|
* contexts in which one might want to emit events. It is a simple multicast
|
|
* mechanism on top of which extra functionality can be composed. For example, a
|
|
* more advanced emitter may use an EventHolder and EventFactory.
|
|
*/
|
|
class EventEmitter<EventDefinitions: {...}> {
|
|
_subscriber: EventSubscriptionVendor<EventDefinitions> = new EventSubscriptionVendor<EventDefinitions>();
|
|
|
|
/**
|
|
* @constructor
|
|
*/
|
|
constructor(subscriber: ?EventSubscriptionVendor<EventDefinitions>) {
|
|
if (subscriber != null) {
|
|
console.warn('EventEmitter(...): Constructor argument is deprecated.');
|
|
this._subscriber = subscriber;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a listener to be invoked when events of the specified type are
|
|
* emitted. An optional calling context may be provided. The data arguments
|
|
* emitted will be passed to the listener function.
|
|
*
|
|
* @param {string} eventType - Name of the event to listen to
|
|
* @param {function} listener - Function to invoke when the specified event is
|
|
* emitted
|
|
* @param {*} context - Optional context object to use when invoking the
|
|
* listener
|
|
*/
|
|
addListener<K: $Keys<EventDefinitions>>(
|
|
eventType: K,
|
|
// FIXME: listeners should return void instead of mixed to prevent issues
|
|
listener: (...$ElementType<EventDefinitions, K>) => mixed,
|
|
context: $FlowFixMe,
|
|
): EventSubscription {
|
|
return (this._subscriber.addSubscription(
|
|
eventType,
|
|
new EmitterSubscription(this, this._subscriber, listener, context),
|
|
): $FlowFixMe);
|
|
}
|
|
|
|
/**
|
|
* Removes all of the registered listeners, including those registered as
|
|
* listener maps.
|
|
*
|
|
* @param {?string} eventType - Optional name of the event whose registered
|
|
* listeners to remove
|
|
*/
|
|
removeAllListeners<K: $Keys<EventDefinitions>>(eventType: ?K): void {
|
|
this._subscriber.removeAllSubscriptions(eventType);
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use `remove` on the EventSubscription from `addListener`.
|
|
*/
|
|
removeSubscription<K: $Keys<EventDefinitions>>(
|
|
subscription: EmitterSubscription<EventDefinitions, K>,
|
|
): void {
|
|
console.warn(
|
|
'EventEmitter.removeSubscription(...): Method has been deprecated. ' +
|
|
'Please instead use `remove()` on the subscription itself.',
|
|
);
|
|
this.__removeSubscription(subscription);
|
|
}
|
|
|
|
/**
|
|
* Called by `EmitterSubscription` to bypass the above deprecation warning.
|
|
*/
|
|
__removeSubscription<K: $Keys<EventDefinitions>>(
|
|
subscription: EmitterSubscription<EventDefinitions, K>,
|
|
): void {
|
|
invariant(
|
|
subscription.emitter === this,
|
|
'Subscription does not belong to this emitter.',
|
|
);
|
|
this._subscriber.removeSubscription(subscription);
|
|
}
|
|
|
|
/**
|
|
* Returns the number of listeners that are currently registered for the given
|
|
* event.
|
|
*
|
|
* @param {string} eventType - Name of the event to query
|
|
* @returns {number}
|
|
*/
|
|
listenerCount<K: $Keys<EventDefinitions>>(eventType: K): number {
|
|
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
|
return subscriptions
|
|
? // We filter out missing entries because the array is sparse.
|
|
// "callbackfn is called only for elements of the array which actually
|
|
// exist; it is not called for missing elements of the array."
|
|
// https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.filter
|
|
subscriptions.filter(sparseFilterPredicate).length
|
|
: 0;
|
|
}
|
|
|
|
/**
|
|
* Emits an event of the given type with the given data. All handlers of that
|
|
* particular type will be notified.
|
|
*
|
|
* @param {string} eventType - Name of the event to emit
|
|
* @param {...*} Arbitrary arguments to be passed to each registered listener
|
|
*
|
|
* @example
|
|
* emitter.addListener('someEvent', function(message) {
|
|
* console.log(message);
|
|
* });
|
|
*
|
|
* emitter.emit('someEvent', 'abc'); // logs 'abc'
|
|
*/
|
|
emit<K: $Keys<EventDefinitions>>(
|
|
eventType: K,
|
|
...args: $ElementType<EventDefinitions, K>
|
|
): void {
|
|
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
|
if (subscriptions) {
|
|
for (let i = 0, l = subscriptions.length; i < l; i++) {
|
|
const subscription = subscriptions[i];
|
|
|
|
// The subscription may have been removed during this event loop.
|
|
if (subscription && subscription.listener) {
|
|
subscription.listener.apply(subscription.context, args);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated Use `remove` on the EventSubscription from `addListener`.
|
|
*/
|
|
removeListener<K: $Keys<EventDefinitions>>(
|
|
eventType: K,
|
|
// FIXME: listeners should return void instead of mixed to prevent issues
|
|
listener: (...$ElementType<EventDefinitions, K>) => mixed,
|
|
): void {
|
|
console.warn(
|
|
`EventEmitter.removeListener('${eventType}', ...): Method has been ` +
|
|
'deprecated. Please instead use `remove()` on the subscription ' +
|
|
'returned by `EventEmitter.addListener`.',
|
|
);
|
|
const subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
|
if (subscriptions) {
|
|
for (let i = 0, l = subscriptions.length; i < l; i++) {
|
|
const subscription = subscriptions[i];
|
|
|
|
// The subscription may have been removed during this event loop.
|
|
// its listener matches the listener in method parameters
|
|
if (subscription && subscription.listener === listener) {
|
|
subscription.remove();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = EventEmitter;
|