Skip to content

Commit

Permalink
Merge pull request #85 from WordPress/update/run-hooks-perf
Browse files Browse the repository at this point in the history
Hooks: Micro-optimize runHooks
  • Loading branch information
aduth committed Feb 27, 2018
2 parents e116f2a + 8d5854b commit d0c807d
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 41 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
},
"devDependencies": {
"babel-core": "^6.26.0",
"benchmark": "^2.1.4",
"chalk": "^2.0.1",
"check-node-version": "^3.1.1",
"codecov": "^2.2.0",
Expand Down
18 changes: 18 additions & 0 deletions packages/hooks/benchmark/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const Benchmark = require( 'benchmark' );
const hooks = require( '../' );

const suite = new Benchmark.Suite;

function myCallback() {}

hooks.addFilter( 'handled', 'myCallback', myCallback );

suite
.add( 'handled', () => {
hooks.applyFilters( 'handled' );
} )
.add( 'unhandled', () => {
hooks.applyFilters( 'unhandled' );
} )
.on( 'cycle', ( event ) => console.log( event.target.toString() ) )
.run( { async: true } );
2 changes: 1 addition & 1 deletion packages/hooks/src/createAddHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function createAddHook( hooks ) {

const handler = { callback, priority, namespace };

if ( hooks.hasOwnProperty( hookName ) ) {
if ( hooks[ hookName ] ) {
// Find the correct insert index of the new hook.
const handlers = hooks[ hookName ].handlers;
let i = 0;
Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/src/createDidHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function createDidHook( hooks ) {
return;
}

return hooks.hasOwnProperty( hookName ) && hooks[ hookName ].runs
return hooks[ hookName ] && hooks[ hookName ].runs
? hooks[ hookName ].runs
: 0;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/src/createHasHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function createHasHook( hooks ) {
* the given hook.
*/
return function hasHook( hookName ) {
return hooks.hasOwnProperty( hookName )
return hooks[ hookName ]
? hooks[ hookName ].handlers.length
: 0;
};
Expand Down
6 changes: 4 additions & 2 deletions packages/hooks/src/createHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import createDidHook from './createDidHook';
* @return {Object} Object that contains all hooks.
*/
function createHooks() {
const actions = {};
const filters = {};
const actions = Object.create( null );
const filters = Object.create( null );
actions.__current = [];
filters.__current = [];

return {
addAction: createAddHook( actions ),
Expand Down
2 changes: 1 addition & 1 deletion packages/hooks/src/createRemoveHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function createRemoveHook( hooks, removeAll ) {
}

// Bail if no hooks exist by this name
if ( ! hooks.hasOwnProperty( hookName ) ) {
if ( ! hooks[ hookName ] ) {
return 0;
}

Expand Down
34 changes: 13 additions & 21 deletions packages/hooks/src/createRunHook.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,12 @@ function createRunHook( hooks, returnFirstArg ) {
* @return {*} Return value of runner, if applicable.
*/
return function runHooks( hookName, ...args ) {

if ( ! validateHookName( hookName ) ) {
return;
}

if ( ! hooks.hasOwnProperty( hookName ) ) {
hooks[ hookName ] = {
runs: 0,
handlers: [],
};
let handlers;
if ( hooks[ hookName ] ) {
handlers = hooks[ hookName ].handlers;
}

const handlers = hooks[ hookName ].handlers;

if ( ! handlers.length ) {
if ( ! handlers || ! handlers.length ) {
return returnFirstArg
? args[ 0 ]
: undefined;
Expand All @@ -46,25 +37,26 @@ function createRunHook( hooks, returnFirstArg ) {
currentIndex: 0,
};

hooks.__current = hooks.__current || [];
hooks.__current.push( hookInfo );
hooks[ hookName ].runs++;

let maybeReturnValue = args[ 0 ];
if ( ! hooks[ hookName ] ) {
hooks[ hookName ] = {
runs: 0,
handlers: [],
};
}
hooks[ hookName ].runs++;

while ( hookInfo.currentIndex < handlers.length ) {
const handler = handlers[ hookInfo.currentIndex ];
maybeReturnValue = handler.callback.apply( null, args );
if ( returnFirstArg ) {
args[ 0 ] = maybeReturnValue;
}
args[ 0 ] = handler.callback.apply( null, args );
hookInfo.currentIndex++;
}

hooks.__current.pop();

if ( returnFirstArg ) {
return maybeReturnValue;
return args[ 0 ];
}
};
}
Expand Down
18 changes: 4 additions & 14 deletions packages/hooks/src/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ beforeEach( () => {
// because the internal functions have references to the original objects.
[ actions, filters ].forEach( hooks => {
for ( const k in hooks ) {
if ( '__current' === k ) {
continue;
}

delete hooks[ k ];
}
} );
Expand Down Expand Up @@ -214,20 +218,6 @@ test( 'cannot add filters with non-numeric priorities', () => {
);
} );

test( 'cannot run filters with non-string names', () => {
expect( applyFilters( () => {}, 42 ) ).toBe( undefined );
expect( console ).toHaveErroredWith(
'The hook name must be a non-empty string.'
);
} );

test( 'cannot run filters named with __ prefix', () => {
expect( applyFilters( '__test', 42 ) ).toBe( undefined );
expect( console ).toHaveErroredWith(
'The hook name cannot begin with `__`.'
);
} );

test( 'add 3 filters with different priorities and run them', () => {
addFilter( 'test.filter', 'my_callback_filter_a', filter_a );
addFilter( 'test.filter', 'my_callback_filter_b', filter_b, 2 );
Expand Down

0 comments on commit d0c807d

Please sign in to comment.