Skip to content
This repository has been archived by the owner on Jul 2, 2021. It is now read-only.

Commit

Permalink
Sync from internal, prep v3 (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
zpao committed Apr 21, 2017
1 parent c2b3571 commit 1276815
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 68 deletions.
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -13,7 +13,7 @@
"index.js",
"lib/"
],
"main": "index.js",
"main": "lib/EventEmitter.js",
"repository": "facebook/emitter",
"scripts": {
"build": "gulp build",
Expand Down
75 changes: 44 additions & 31 deletions src/BaseEventEmitter.js
Expand Up @@ -7,14 +7,17 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule BaseEventEmitter
* @typechecks
* @flow
*/

var EmitterSubscription = require('EmitterSubscription');
var EventSubscriptionVendor = require('EventSubscriptionVendor');
const EmitterSubscription = require('EmitterSubscription');
const ErrorUtils = require('ErrorUtils');
const EventSubscriptionVendor = require('EventSubscriptionVendor');

var emptyFunction = require('emptyFunction');
var invariant = require('invariant');
const emptyFunction = require('emptyFunction');
const invariant = require('invariant');

import type EventSubscription from 'EventSubscription';

/**
* @class BaseEventEmitter
Expand All @@ -29,11 +32,14 @@ var invariant = require('invariant');
* mechanism on top of which extra functionality can be composed. For example, a
* more advanced emitter may use an EventHolder and EventFactory.
*/
class BaseEventEmitter {
class BaseEventEmitter<TEvent: string> {
_currentSubscription: ?EmitterSubscription;
_subscriber: EventSubscriptionVendor;

/**
* @constructor
*/
constructor() {
constructor(): void {
this._subscriber = new EventSubscriptionVendor();
this._currentSubscription = null;
}
Expand All @@ -53,7 +59,10 @@ class BaseEventEmitter {
* listener
*/
addListener(
eventType: string, listener, context: ?Object): EmitterSubscription {
eventType: TEvent,
listener: Function,
context: ?Object,
): EmitterSubscription {
return this._subscriber.addSubscription(
eventType,
new EmitterSubscription(this._subscriber, listener, context));
Expand All @@ -69,7 +78,11 @@ class BaseEventEmitter {
* @param {*} context - Optional context object to use when invoking the
* listener
*/
once(eventType: string, listener, context: ?Object): EmitterSubscription {
once(
eventType: TEvent,
listener: Function,
context: ?Object,
): EmitterSubscription {
var emitter = this;
return this.addListener(eventType, function() {
emitter.removeCurrentListener();
Expand All @@ -84,32 +97,21 @@ class BaseEventEmitter {
* @param {?string} eventType - Optional name of the event whose registered
* listeners to remove
*/
removeAllListeners(eventType: ?String) {
removeAllListeners(eventType: ?TEvent): void {
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.
* object that can remove the listener 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() {
removeCurrentListener(): void {
invariant(
!!this._currentSubscription,
'Not in an emitting cycle; there is no current subscription'
Expand All @@ -124,7 +126,7 @@ class BaseEventEmitter {
* @param {string} eventType - Name of the event to query
* @return {array}
*/
listeners(eventType: string): Array /* TODO: Array<EventSubscription> */ {
listeners(eventType: ?TEvent): Array<EventSubscription> {
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
return subscriptions
? subscriptions.filter(emptyFunction.thatReturnsTrue).map(
Expand All @@ -148,20 +150,26 @@ class BaseEventEmitter {
*
* emitter.emit('someEvent', 'abc'); // logs 'abc'
*/
emit(eventType) {
emit(eventType: TEvent): void {
var subscriptions = this._subscriber.getSubscriptionsForType(eventType);
if (subscriptions) {
var keys = Object.keys(subscriptions);
var args;
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;
this.__emitToSubscription.apply(
this,
[subscription].concat(Array.prototype.slice.call(arguments))
);
if (args == null) {
args = [subscription];
for (var i = 0, len = arguments.length; i < len; i++) {
args[i + 1] = arguments[i];
}
} else {
args[0] = subscription;
}
this.__emitToSubscription.apply(this, args);
}
}
this._currentSubscription = null;
Expand All @@ -177,8 +185,13 @@ class BaseEventEmitter {
* @param {string} eventType
* @param {*} Arbitrary arguments to be passed to each registered listener
*/
__emitToSubscription(subscription, eventType) {
var args = Array.prototype.slice.call(arguments, 2);
__emitToSubscription(
subscription: EmitterSubscription,
eventType: TEvent,
...args: Array<mixed>
): void {
// Note: internally we use ErrorUtils.applyWithGuard
// We should add some version of that to fbjs but for now we won't guard.
subscription.listener.apply(subscription.context, args);
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/EmitterSubscription.js
Expand Up @@ -5,19 +5,23 @@
* 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 EmitterSubscription
* @typechecks
* @flow
*/

'use strict';

var EventSubscription = require('EventSubscription');
const EventSubscription = require('EventSubscription');

import type EventSubscriptionVendor from 'EventSubscriptionVendor';

/**
* EmitterSubscription represents a subscription with listener and context data.
*/
class EmitterSubscription extends EventSubscription {
context: ?Object;
listener: Function;

/**
* @param {EventSubscriptionVendor} subscriber - The subscriber that controls
Expand All @@ -27,7 +31,11 @@ class EmitterSubscription extends EventSubscription {
* @param {*} context - Optional context object to use when invoking the
* listener
*/
constructor(subscriber: EventSubscriptionVendor, listener, context: ?Object) {
constructor(
subscriber: EventSubscriptionVendor,
listener: Function,
context: ?Object,
): void {
super(subscriber);
this.listener = listener;
this.context = context;
Expand Down
9 changes: 6 additions & 3 deletions src/EventSubscription.js
Expand Up @@ -7,29 +7,32 @@
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule EventSubscription
* @typechecks
* @flow
*/

'use strict';

import type EventSubscriptionVendor from 'EventSubscriptionVendor';

/**
* EventSubscription represents a subscription to a particular event. It can
* remove its own subscription.
*/
class EventSubscription {
subscriber: EventSubscriptionVendor;

/**
* @param {EventSubscriptionVendor} subscriber the subscriber that controls
* this subscription.
*/
constructor(subscriber: EventSubscriptionVendor) {
constructor(subscriber: EventSubscriptionVendor): void {
this.subscriber = subscriber;
}

/**
* Removes this subscription from the subscriber that controls it.
*/
remove() {
remove(): void {
if (this.subscriber) {
this.subscriber.removeSubscription(this);
this.subscriber = null;
Expand Down
14 changes: 7 additions & 7 deletions src/EventSubscriptionVendor.js
Expand Up @@ -5,14 +5,15 @@
* 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 EventSubscriptionVendor
* @typechecks
* @noflow
*/

'use strict';

var invariant = require('invariant');
const invariant = require('invariant');

/**
* EventSubscriptionVendor stores a set of EventSubscriptions that are
Expand All @@ -22,7 +23,6 @@ class EventSubscriptionVendor {

constructor() {
this._subscriptionsForType = {};
this._currentSubscription = null;
}

/**
Expand All @@ -39,7 +39,7 @@ class EventSubscriptionVendor {
if (!this._subscriptionsForType[eventType]) {
this._subscriptionsForType[eventType] = [];
}
var key = this._subscriptionsForType[eventType].length;
const key = this._subscriptionsForType[eventType].length;
this._subscriptionsForType[eventType].push(subscription);
subscription.eventType = eventType;
subscription.key = key;
Expand Down Expand Up @@ -67,10 +67,10 @@ class EventSubscriptionVendor {
* @param {object} subscription
*/
removeSubscription(subscription: Object) {
var eventType = subscription.eventType;
var key = subscription.key;
const eventType = subscription.eventType;
const key = subscription.key;

var subscriptionsForType = this._subscriptionsForType[eventType];
const subscriptionsForType = this._subscriptionsForType[eventType];
if (subscriptionsForType) {
delete subscriptionsForType[key];
}
Expand Down

0 comments on commit 1276815

Please sign in to comment.