Skip to content

Instantly share code, notes, and snippets.

@jesperbjensen
Created October 8, 2015 16:07
Show Gist options
  • Save jesperbjensen/ab0d25868e2abac79c0f to your computer and use it in GitHub Desktop.
Save jesperbjensen/ab0d25868e2abac79c0f to your computer and use it in GitHub Desktop.
A TypeScript conversion of the React Flux Dispatcher
class Dispatcher {
_callbacks: { [key: string]: (payload: IActionPayload) => void };
_isDispatching: boolean;
_isHandled: { [key: string]: boolean };
_isPending: { [key: string]: boolean };
_lastID: number;
_pendingPayload: IActionPayload;
constructor() {
this._callbacks = {};
this._isDispatching = false;
this._isHandled = {};
this._isPending = {};
this._lastID = 1;
}
/**
* Registers a callback to be invoked with every dispatched payload. Returns
* a token that can be used with `waitFor()`.
*/
register(callback: (payload: IActionPayload) => void): string {
var id = _prefix + this._lastID++;
this._callbacks[id] = callback;
return id;
}
/**
* Removes a callback based on its token.
*/
unregister(id: string): void {
if (!this._callbacks[id]) {
throw 'Dispatcher.unregister(...): "+ id +" does not map to a registered callback.';
}
delete this._callbacks[id];
}
/**
* Waits for the callbacks specified to be invoked before continuing execution
* of the current callback. This method should only be used by a callback in
* response to a dispatched payload.
*/
waitFor(ids: string[]): void {
if (!this._isDispatching) {
throw 'Dispatcher.waitFor(...): Must be invoked while dispatching.'
}
for (var ii = 0; ii < ids.length; ii++) {
var id = ids[ii];
if (this._isPending[id]) {
if (!this._isHandled[id]) {
throw 'Dispatcher.waitFor(...): Circular dependency detected while waiting for ' + id;
}
continue;
}
if (!this._callbacks[id]) {
throw 'Dispatcher.waitFor(...): ' + id + ' does not map to a registered callback.';
}
this._invokeCallback(id);
}
}
/**
* Dispatches a payload to all registered callbacks.
*/
dispatch(payload: IActionPayload): void {
console.debug("Dispatching: " + payload.action);
if (this._isDispatching) {
throw 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.';
}
this.startDispatching(payload);
try {
for (var id in this._callbacks) {
if (this._isPending[id]) {
continue;
}
this._invokeCallback(id);
}
} finally {
this.stopDispatching();
}
}
/**
* Is this Dispatcher currently dispatching.
*/
isDispatching(): boolean {
return this._isDispatching;
}
/**
* Call the callback stored with the given id. Also do some internal
* bookkeeping.
*/
_invokeCallback(id: string): void {
this._isPending[id] = true;
this._callbacks[id](this._pendingPayload);
this._isHandled[id] = true;
}
/**
* Set up bookkeeping needed when dispatching.
*/
private startDispatching(payload: IActionPayload): void {
for (var id in this._callbacks) {
this._isPending[id] = false;
this._isHandled[id] = false;
}
this._pendingPayload = payload;
this._isDispatching = true;
}
/**
* Clear bookkeeping used for dispatching.
*/
private stopDispatching(): void {
delete this._pendingPayload;
this._isDispatching = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment