Dispatcher

Dispatcher is used to broadcast payloads to registered callbacks. This is different from generic pub-sub systems in two ways:

  • Callbacks are not subscribed to particular events. Every payload is dispatched to every registered callback.
  • Callbacks can be deferred in whole or part until other callbacks have been executed.

Check out Dispatcher.js for the source code.

API #

  • register(function callback): string Registers a callback to be invoked with every dispatched payload. Returns a token that can be used with waitFor().

  • unregister(string id): void Removes a callback based on its token.

  • waitFor(array<string> ids): void 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.

  • dispatch(object payload): void Dispatches a payload to all registered callbacks.

  • isDispatching(): boolean Is this Dispatcher currently dispatching.

Example #

For example, consider this hypothetical flight destination form, which selects a default city when a country is selected:

var flightDispatcher = new Dispatcher(); // Keeps track of which country is selected var CountryStore = {country: null}; // Keeps track of which city is selected var CityStore = {city: null}; // Keeps track of the base flight price of the selected city var FlightPriceStore = {price: null};

When a user changes the selected city, we dispatch the payload:

flightDispatcher.dispatch({ actionType: 'city-update', selectedCity: 'paris' });

This payload is digested by CityStore:

flightDispatcher.register(function(payload) { if (payload.actionType === 'city-update') { CityStore.city = payload.selectedCity; } });

When the user selects a country, we dispatch the payload:

flightDispatcher.dispatch({ actionType: 'country-update', selectedCountry: 'australia' });

This payload is digested by both stores:

CountryStore.dispatchToken = flightDispatcher.register(function(payload) { if (payload.actionType === 'country-update') { CountryStore.country = payload.selectedCountry; } });

When the callback to update CountryStore is registered, we save a reference to the returned token. Using this token with waitFor(), we can guarantee that CountryStore is updated before the callback that updates CityStore needs to query its data.

CityStore.dispatchToken = flightDispatcher.register(function(payload) { if (payload.actionType === 'country-update') { // `CountryStore.country` may not be updated. flightDispatcher.waitFor([CountryStore.dispatchToken]); // `CountryStore.country` is now guaranteed to be updated. // Select the default city for the new country CityStore.city = getDefaultCityForCountry(CountryStore.country); } });

The usage of waitFor() can be chained, for example:

FlightPriceStore.dispatchToken = flightDispatcher.register(function(payload) { switch (payload.actionType) { case 'country-update': case 'city-update': flightDispatcher.waitFor([CityStore.dispatchToken]); FlightPriceStore.price = getFlightPriceStore(CountryStore.country, CityStore.city); break; } });

The country-update payload will be guaranteed to invoke the stores' registered callbacks in order: CountryStore, CityStore, then FlightPriceStore.