From eb5a5eab8380bcc87628c5c1ce205f8d80c62bb8 Mon Sep 17 00:00:00 2001 From: Luca Mussi Date: Mon, 25 Jul 2016 00:13:58 +0200 Subject: [PATCH] avoid useless calls to listeners --- src/createStore.js | 19 +++++++++++++++---- test/createStore.spec.js | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/createStore.js b/src/createStore.js index 8fdfad3575..cc76121876 100644 --- a/src/createStore.js +++ b/src/createStore.js @@ -58,6 +58,8 @@ export default function createStore(reducer, preloadedState, enhancer) { var currentState = preloadedState var currentListeners = [] var nextListeners = currentListeners + var listeners = [] + var listenerId = 0 var isDispatching = false function ensureCanMutateNextListeners() { @@ -140,8 +142,14 @@ export default function createStore(reducer, preloadedState, enhancer) { isSubscribed = false ensureCanMutateNextListeners() - var index = nextListeners.indexOf(listener) + let index = nextListeners.indexOf(listener) nextListeners.splice(index, 1) + + index = listeners.indexOf(listener) + if (index !== -1 && index > listenerId) { + listener() + listeners.splice(index, 1) + } } } @@ -196,10 +204,13 @@ export default function createStore(reducer, preloadedState, enhancer) { isDispatching = false } - var listeners = currentListeners = nextListeners - for (var i = 0; i < listeners.length; i++) { - listeners[i]() + listeners = currentListeners = nextListeners + for (listenerId = 0; listenerId < listeners.length; listenerId++) { + listeners[listenerId]() } + currentListeners = nextListeners + listeners = [] + listenerId = 0 return action } diff --git a/test/createStore.spec.js b/test/createStore.spec.js index 6e7df3410b..b9d852a8db 100644 --- a/test/createStore.spec.js +++ b/test/createStore.spec.js @@ -1,13 +1,13 @@ import expect from 'expect' import { createStore, combineReducers } from '../src/index' -import { - addTodo, - dispatchInMiddle, +import { + addTodo, + dispatchInMiddle, getStateInMiddle, subscribeInMiddle, unsubscribeInMiddle, - throwError, - unknownAction + throwError, + unknownAction } from './helpers/actionCreators' import * as reducers from './helpers/reducers' import * as Rx from 'rxjs' @@ -388,18 +388,40 @@ describe('createStore', () => { store.dispatch(unknownAction()) expect(listener1.calls.length).toBe(1) - expect(listener2.calls.length).toBe(2) - expect(listener3.calls.length).toBe(2) + expect(listener2.calls.length).toBe(1) + expect(listener3.calls.length).toBe(1) expect(listener4.calls.length).toBe(1) unsubscribe4() store.dispatch(unknownAction()) expect(listener1.calls.length).toBe(1) - expect(listener2.calls.length).toBe(3) - expect(listener3.calls.length).toBe(3) + expect(listener2.calls.length).toBe(2) + expect(listener3.calls.length).toBe(2) expect(listener4.calls.length).toBe(1) }) + it('notifies a listener unsubscribed with nested dispatch with the new state', () => { + const store = createStore(reducers.todos) + + var firstCall = true + const listener1 = expect.createSpy().andCall(() => { + unsubscribe2() + if (firstCall) { + firstCall = false + store.dispatch(unknownAction()) + } + }) + const listener2 = expect.createSpy() + + store.subscribe(listener1) + let unsubscribe2 = store.subscribe(listener2) + + store.dispatch(unknownAction()) + expect(listener1.calls.length).toBe(2) + expect(listener2.calls.length).toBe(1) + }) + + it('provides an up-to-date state when a subscriber is notified', done => { const store = createStore(reducers.todos) store.subscribe(() => {