mirror of
https://github.com/status-im/react-native.git
synced 2025-01-26 17:30:25 +00:00
db617e56a3
Summary: public Any uncaught exception inside an event emitter handler was reported as softError, which didn't crash the app, but left the app running in an unknown state. Since there's no way for the app to catch these softerror (to provide a fallback error view, etc), let's change it to report fatal error for uncaught exception for the time being. Reviewed By: javache Differential Revision: D2685322 fb-gh-sync-id: 52956d3db20809cc90448bd080795754b899435e
173 lines
5.7 KiB
JavaScript
173 lines
5.7 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule EventEmitter
|
|
* @typechecks
|
|
*/
|
|
|
|
var EmitterSubscription = require('EmitterSubscription');
|
|
var ErrorUtils = require('ErrorUtils');
|
|
var EventSubscriptionVendor = require('EventSubscriptionVendor');
|
|
var emptyFunction = require('emptyFunction');
|
|
var invariant = require('invariant');
|
|
|
|
/**
|
|
* @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 {
|
|
/**
|
|
* @constructor
|
|
*/
|
|
constructor() {
|
|
this._subscriber = new EventSubscriptionVendor();
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*
|
|
* TODO: Annotate the listener arg's type. This is tricky because listeners
|
|
* can be invoked with varargs.
|
|
*
|
|
* @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(
|
|
eventType: String, listener, context: ?Object): EmitterSubscription {
|
|
return this._subscriber.addSubscription(
|
|
eventType,
|
|
new EmitterSubscription(this._subscriber, listener, context));
|
|
}
|
|
|
|
/**
|
|
* Similar to addListener, except that the listener is removed after it is
|
|
* invoked once.
|
|
*
|
|
* @param {string} eventType - Name of the event to listen to
|
|
* @param {function} listener - Function to invoke only once when the
|
|
* specified event is emitted
|
|
* @param {*} context - Optional context object to use when invoking the
|
|
* listener
|
|
*/
|
|
once(eventType: String, listener, context: ?Object): EmitterSubscription {
|
|
var emitter = this;
|
|
return this.addListener(eventType, function() {
|
|
emitter.removeCurrentListener();
|
|
listener.apply(context, arguments);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 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(eventType: ?String) {
|
|
this._subscriber.removeAllSubscriptions(eventType);
|
|
}
|
|
|
|
/**
|
|
* Provides an API that can be called during an eventing cycle to remove the
|
|
* last listener that was invoked. This allows a developer to provide an event
|
|
* object that can remove the listener (or listener map) during the
|
|
* invocation.
|
|
*
|
|
* If it is called when not inside of an emitting cycle it will throw.
|
|
*
|
|
* @throws {Error} When called not during an eventing cycle
|
|
*
|
|
* @example
|
|
* var subscription = emitter.addListenerMap({
|
|
* someEvent: function(data, event) {
|
|
* console.log(data);
|
|
* emitter.removeCurrentListener();
|
|
* }
|
|
* });
|
|
*
|
|
* emitter.emit('someEvent', 'abc'); // logs 'abc'
|
|
* emitter.emit('someEvent', 'def'); // does not log anything
|
|
*/
|
|
removeCurrentListener() {
|
|
invariant(
|
|
!!this._currentSubscription,
|
|
'Not in an emitting cycle; there is no current subscription'
|
|
);
|
|
this._subscriber.removeSubscription(this._currentSubscription);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of listeners that are currently registered for the given
|
|
* event.
|
|
*
|
|
* @param {string} eventType - Name of the event to query
|
|
* @returns {array}
|
|
*/
|
|
listeners(eventType: String): Array /* TODO: Array<EventSubscription> */ {
|
|
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
|
return subscriptions
|
|
? subscriptions.filter(emptyFunction.thatReturnsTrue).map(
|
|
function(subscription) {
|
|
return subscription.listener;
|
|
})
|
|
: [];
|
|
}
|
|
|
|
/**
|
|
* 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(eventType: String) {
|
|
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
|
|
if (subscriptions) {
|
|
var keys = Object.keys(subscriptions);
|
|
for (var ii = 0; ii < keys.length; ii++) {
|
|
var key = keys[ii];
|
|
var subscription = subscriptions[key];
|
|
|
|
// The subscription may have been removed during this event loop.
|
|
if (subscription) {
|
|
this._currentSubscription = subscription;
|
|
subscription.listener.apply(
|
|
subscription.context,
|
|
Array.prototype.slice.call(arguments, 1)
|
|
);
|
|
}
|
|
}
|
|
this._currentSubscription = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = EventEmitter;
|