From 6ed2ca6caaf2fe5d2082215c8b43508a74f061c5 Mon Sep 17 00:00:00 2001 From: griffpatch Date: Mon, 20 Nov 2017 15:22:51 +0000 Subject: [PATCH] Cache Block Inputs & Procedure Definitions * Cache Block Inputs & Procedure Definitions * @mzgoddard requested changes on this pull request * Move all caching into a single reusable field _cache. * Invalidate 'all' caches on any change. * Use 'typeof' instead of hasOwnProperty. * Take caching out of Block and use lookup instead. --- src/engine/blocks.js | 73 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/src/engine/blocks.js b/src/engine/blocks.js index 2f2de7b40..8776c6f6c 100644 --- a/src/engine/blocks.js +++ b/src/engine/blocks.js @@ -25,6 +25,30 @@ class Blocks { * @type {Array.} */ this._scripts = []; + + /** + * Runtime Cache + * @type {{inputs: {}, procedureParamNames: {}, procedureDefinitions: {}}} + * @private + */ + this._cache = { + /** + * Cache block inputs by block id + * @type {object.>} + */ + inputs: {}, + /** + * Cache procedure Param Names by block id + * @type {object.>} + */ + procedureParamNames: {}, + /** + * Cache procedure definitions by block id + * @type {object.} + */ + procedureDefinitions: {} + }; + } /** @@ -105,11 +129,16 @@ class Blocks { /** * Get all non-branch inputs for a block. * @param {?object} block the block to query. - * @return {!object} All non-branch inputs and their associated blocks. + * @return {?Array.} All non-branch inputs and their associated blocks. */ getInputs (block) { if (typeof block === 'undefined') return null; - const inputs = {}; + let inputs = this._cache.inputs[block.id]; + if (typeof inputs !== 'undefined') { + return inputs; + } + + inputs = {}; for (const input in block.inputs) { // Ignore blocks prefixed with branch prefix. if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) !== @@ -117,6 +146,8 @@ class Blocks { inputs[input] = block.inputs[input]; } } + + this._cache.inputs[block.id] = inputs; return inputs; } @@ -149,16 +180,24 @@ class Blocks { * @return {?string} ID of procedure definition. */ getProcedureDefinition (name) { + const blockID = this._cache.procedureDefinitions[name]; + if (typeof blockID !== 'undefined') { + return blockID; + } + for (const id in this._blocks) { if (!this._blocks.hasOwnProperty(id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_definition') { const internal = this._getCustomBlockInternal(block); if (internal && internal.mutation.proccode === name) { - return id; // The outer define block id + this._cache.procedureDefinitions[name] = id; // The outer define block id + return id; } } } + + this._cache.procedureDefinitions[name] = null; return null; } @@ -168,14 +207,23 @@ class Blocks { * @return {?Array.} List of param names for a procedure. */ getProcedureParamNames (name) { + const cachedNames = this._cache.procedureParamNames[name]; + if (typeof cachedNames !== 'undefined') { + return cachedNames; + } + for (const id in this._blocks) { if (!this._blocks.hasOwnProperty(id)) continue; const block = this._blocks[id]; if (block.opcode === 'procedures_prototype' && block.mutation.proccode === name) { - return JSON.parse(block.mutation.argumentnames); + const paramNames = JSON.parse(block.mutation.argumentnames); + this._cache.procedureParamNames[name] = paramNames; + return paramNames; } } + + this._cache.procedureParamNames[name] = null; return null; } @@ -271,6 +319,15 @@ class Blocks { // --------------------------------------------------------------------- + /** + * Reset all runtime caches. + */ + resetCache () { + this._cache.inputs = {}; + this._cache.procedureParamNames = {}; + this._cache.procedureDefinitions = {}; + } + /** * Block management: create blocks and scripts from a `create` event * @param {!object} block Blockly create event to be processed @@ -289,6 +346,8 @@ class Blocks { if (block.topLevel) { this._addScript(block.id); } + + this.resetCache(); } /** @@ -301,7 +360,6 @@ class Blocks { if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return; const block = this._blocks[args.id]; if (typeof block === 'undefined') return; - const wasMonitored = block.isMonitored; switch (args.element) { case 'field': @@ -337,6 +395,8 @@ class Blocks { } break; } + + this.resetCache(); } /** @@ -393,6 +453,7 @@ class Blocks { } this._blocks[e.id].parent = e.newParent; } + this.resetCache(); } @@ -447,6 +508,8 @@ class Blocks { // Delete block itself. delete this._blocks[blockId]; + + this.resetCache(); } // ---------------------------------------------------------------------