UNPKG

hbus

Version:
182 lines (176 loc) 5.75 kB
class Action { constructor(type, payload) { this.type = type; this.payload = payload; } } function createActionFactory(type, defaultPayload) { const defaultPayloadIsObject = defaultPayload instanceof Object; return (payload) => new Action(type, defaultPayloadIsObject && payload instanceof Object ? Object.assign({}, defaultPayload, payload) : payload); } function createProcessor(processorMap, defaultProcessor) { return (state, action) => { const { type } = action; return (type in processorMap) ? processorMap[type](state, action) : defaultProcessor ? defaultProcessor(state, action) : state; }; } const defaultComparer = (oldState, newState) => { if (oldState === newState && String(oldState) === String(newState) || oldState !== oldState && newState !== newState) { return true; } else { if (!(oldState instanceof Object && newState instanceof Object)) { return false; } for (const oldKey in oldState) { if (!(oldKey in newState && defaultComparer(oldState[oldKey], newState[oldKey]))) { return false; } } for (const newKey in newState) { if (!(newKey in oldState)) { return false; } } return true; } }; const defaultTickMethod = (callback) => { requestAnimationFrame(callback); }; const ticker = { tickMethod: defaultTickMethod, _willTick: false, _callbacks: new Array(), tick(callback) { ticker._callbacks.push(callback); if (!ticker._willTick) { ticker._willTick = true; ticker.tickMethod(() => { ticker._willTick = false; const { _callbacks } = ticker; _callbacks.forEach(cb => { cb(); }); _callbacks.length = 0; }); } } }; class Bus { constructor(processor, defaultState = {}) { this.processor = processor; this.comparer = defaultComparer; this._stateRequestCallbacks = new Array(); this._willUpdate = false; this._actions = new Array(); this._subscriberMap = new Map(); this._subscribers = new Array(); this._state = defaultState; } _requestUdpate() { if (!this._willUpdate) { this._willUpdate = true; ticker.tick(() => { this._willUpdate = false; this._update(); const { _stateRequestCallbacks, _state } = this; _stateRequestCallbacks.forEach(callback => { callback(_state); }); _stateRequestCallbacks.length = 0; }); } } _update() { const { processor, comparer, _state, _actions, _subscriberMap } = this; // @ts-ignore let newState = _state instanceof Object ? Object.create(_state) : _state, t; _actions.forEach(action => { t = processor(newState, action); if (t !== undefined) { newState = t; } }); _actions.length = 0; this._state = newState; let hasChanged = false; _subscriberMap.forEach((subscribers, propName) => { const prop = newState[propName]; if (!comparer(prop, _state[propName])) { hasChanged = true; subscribers.forEach(subscriber => { subscriber(prop); }); } }); if (hasChanged || !comparer(_state, newState)) { this._subscribers.forEach(subscriber => { subscriber(newState); }); } } getState() { return this._state; } requestState(callback) { this._stateRequestCallbacks.push(callback); this._requestUdpate(); return this; } publish(action) { this._actions.push(action); this._requestUdpate(); return this; } subscribe(subscriber) { this._subscribers.push(subscriber); return this; } unsubscribe(subscriber) { const { _subscribers } = this, index = _subscribers.indexOf(subscriber); if (index >= 0) { _subscribers.splice(index, 1); } return this; } clearSubscribers() { this._subscribers.length = 0; return this; } subscribeProp(propName, subscriber) { const { _subscriberMap } = this; let subscribers = _subscriberMap.get(propName); if (!subscribers) { _subscriberMap.set(propName, subscribers = []); } subscribers.push(subscriber); return this; } unsubscribeProp(propName, subscriber) { const { _subscriberMap } = this, subscribers = _subscriberMap.get(propName); if (subscribers) { const index = subscribers.indexOf(subscriber); if (index >= 0) { subscribers.splice(index, 1); } } return this; } clearPropSubscribers(propName) { this._subscriberMap.delete(propName); return this; } clearAllPropSubscribers() { this._subscriberMap.clear(); return this; } clearAllSubscribers() { return this.clearSubscribers().clearAllPropSubscribers(); } } export { Action, createActionFactory, createProcessor, defaultComparer, defaultTickMethod, ticker, Bus };