Code coverage report for ReactFlux/lib/dispatcher.js

Statements: 96.61% (57 / 59)      Branches: 100% (22 / 22)      Functions: 88.89% (16 / 18)      Lines: 96.61% (57 / 59)      Ignored: none     

All files » ReactFlux/lib/ » dispatcher.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 1681 1 1 1 1         1         1     1                 173 1   172   172 1     171 1     170 170 170 170                   40 40       40         80 40     40 40   40   40   314 314 314 314             314 314 277     37 37               40 40                         210 18                   210               37 37                 40 40 40 40 314 314 314                     40 40 40 40 40         1  
var Promise = Promise || require('promise');
var _merge = require('lodash-node/modern/object/merge');
var _isArray = require('lodash-node/modern/lang/isArray');
var _isString = require('lodash-node/modern/lang/isString');
var _forEach = require('lodash-node/modern/collection/forEach');
 
/**
 * Dispatcher
 */
function Dispatcher() {
	/**
	 * Registry of callbacks, waitFor, promises, etc
	 * each constant has it's own array of callbacks, waitFor, promises, etc
	 */
	this._registry = {};
}
 
Dispatcher.prototype = _merge(Dispatcher.prototype, {
 
	/**
	 * Registers a callback
	 * @param {string} constant
	 * @param {function} callback
	 * @param {array|null} waitFor Array indexes to callbacks
	 */
	register: function (constant, callback, waitForIndexes) {
		if (!_isString(constant) || !constant.length) {
			throw new Error('Dispatcher.register: constant must be a string');
		}
		waitForIndexes = waitForIndexes || null;
 
		if (typeof callback != 'function') {
			throw new Error('Dispatcher.register expects second parameter to be a callback');
		}
 
		if (waitForIndexes !== null && !_isArray(waitForIndexes)) {
			throw new Error('Dispatcher.register expects third parameter to be null or an array');
		}
 
		var registry = this._getRegistry(constant);
		registry.callbacks.push(callback);
		registry.waitFor.push(waitForIndexes);
		return registry.callbacks.length - 1;
	},
 
 
	/**
	 * Dispatch
	 * @param {string} constant
	 * @param {object} payload
	 */
	dispatch: function (constant, payload) {
		var registry = this._getRegistry(constant);
		registry.dispatchQueue.push({
			constant: constant,
			payload: payload
		});
		this._dispatch(registry);
	},
 
	_dispatch: function (registry) {
 
		if (registry.isDispatching || !registry.dispatchQueue.length) {
			return;
		}
 
		registry.isDispatching = true;
		var job = registry.dispatchQueue.shift();
 
		this._createDispatchPromises(registry);
 
		_forEach(registry.callbacks, function (callback, idx) {
 
			var resolver = (function (registry, idx, payload) {
				return function () {
					Promise.resolve(registry.callbacks[idx](payload)).then(function () {
						registry.resolves[idx](payload);
					}, function () {
						registry.rejects[idx](new Error('Dispatch callback error'));
					});
				};
			})(registry, idx, job.payload);
 
			var waitFor = registry.waitFor[idx];
			if (!waitFor) {
				resolver();
			}
			else {
				var promisesToWaitFor = this._getPromisesByIndexes(registry, waitFor);
				Promise.all(promisesToWaitFor).then(
					resolver,
					resolver  //Should we really resolve the callback here?
					// Some of the WaitForStores callbacks rejected the request
				);
			}
		}.bind(this));//_forEach(registry.callbacks,
 
		Promise.all(registry.promises).then(function () {
			this._onDispatchEnd(registry);
		}.bind(this), function () {
			this._onDispatchEnd(registry);
		});
 
	},//dispatch
 
 
	/**
	 * Gets a registry for a constant
	 * @param {string} constant
	 */
	_getRegistry: function (constant) {
		if (typeof this._registry[constant] == "undefined") {
			this._registry[constant] = {
				callbacks: [],
				waitFor: [],
				promises: [],
				resolves: [],
				rejects: [],
				dispatchQueue: [],
				isDispatching: false
			};
		}
		return this._registry[constant];
	},
 
	/**
	 * @param {object} registry
	 * @param {array} callbacks
	 */
	_getPromisesByIndexes: function (registry, indexes) {
		return indexes.map(function (idx) {
			return registry.promises[idx];
		});
	},
 
	/**
	 * Create promises for all callbacks in this registry
	 * @param {object} registry
	 */
	_createDispatchPromises: function (registry) {
		registry.promises = [];
		registry.resolves = [];
		registry.rejects = [];
		_forEach(registry.callbacks, function (callback, i) {
			registry.promises[i] = new Promise(function (resolve, reject) {
				registry.resolves[i] = resolve;
				registry.rejects[i] = reject;
			});
		});
	},
 
 
	/**
	 * Clean registry
	 * @param {object} registry
	 */
	_onDispatchEnd: function (registry) {
		registry.promises = [];
		registry.resolves = [];
		registry.rejects = [];
		registry.isDispatching = false;
		this._dispatch(registry);
	}
 
});
 
module.exports = Dispatcher;