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.
This commit is contained in:
griffpatch 2017-11-20 15:22:51 +00:00 committed by Andrew Sliwinski
parent 8ce20fd308
commit 6ed2ca6caa

View file

@ -25,6 +25,30 @@ class Blocks {
* @type {Array.<String>} * @type {Array.<String>}
*/ */
this._scripts = []; this._scripts = [];
/**
* Runtime Cache
* @type {{inputs: {}, procedureParamNames: {}, procedureDefinitions: {}}}
* @private
*/
this._cache = {
/**
* Cache block inputs by block id
* @type {object.<string, !Array.<object>>}
*/
inputs: {},
/**
* Cache procedure Param Names by block id
* @type {object.<string, ?Array.<string>>}
*/
procedureParamNames: {},
/**
* Cache procedure definitions by block id
* @type {object.<string, ?string>}
*/
procedureDefinitions: {}
};
} }
/** /**
@ -105,11 +129,16 @@ class Blocks {
/** /**
* Get all non-branch inputs for a block. * Get all non-branch inputs for a block.
* @param {?object} block the block to query. * @param {?object} block the block to query.
* @return {!object} All non-branch inputs and their associated blocks. * @return {?Array.<object>} All non-branch inputs and their associated blocks.
*/ */
getInputs (block) { getInputs (block) {
if (typeof block === 'undefined') return null; 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) { for (const input in block.inputs) {
// Ignore blocks prefixed with branch prefix. // Ignore blocks prefixed with branch prefix.
if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) !== if (input.substring(0, Blocks.BRANCH_INPUT_PREFIX.length) !==
@ -117,6 +146,8 @@ class Blocks {
inputs[input] = block.inputs[input]; inputs[input] = block.inputs[input];
} }
} }
this._cache.inputs[block.id] = inputs;
return inputs; return inputs;
} }
@ -149,16 +180,24 @@ class Blocks {
* @return {?string} ID of procedure definition. * @return {?string} ID of procedure definition.
*/ */
getProcedureDefinition (name) { getProcedureDefinition (name) {
const blockID = this._cache.procedureDefinitions[name];
if (typeof blockID !== 'undefined') {
return blockID;
}
for (const id in this._blocks) { for (const id in this._blocks) {
if (!this._blocks.hasOwnProperty(id)) continue; if (!this._blocks.hasOwnProperty(id)) continue;
const block = this._blocks[id]; const block = this._blocks[id];
if (block.opcode === 'procedures_definition') { if (block.opcode === 'procedures_definition') {
const internal = this._getCustomBlockInternal(block); const internal = this._getCustomBlockInternal(block);
if (internal && internal.mutation.proccode === name) { 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; return null;
} }
@ -168,14 +207,23 @@ class Blocks {
* @return {?Array.<string>} List of param names for a procedure. * @return {?Array.<string>} List of param names for a procedure.
*/ */
getProcedureParamNames (name) { getProcedureParamNames (name) {
const cachedNames = this._cache.procedureParamNames[name];
if (typeof cachedNames !== 'undefined') {
return cachedNames;
}
for (const id in this._blocks) { for (const id in this._blocks) {
if (!this._blocks.hasOwnProperty(id)) continue; if (!this._blocks.hasOwnProperty(id)) continue;
const block = this._blocks[id]; const block = this._blocks[id];
if (block.opcode === 'procedures_prototype' && if (block.opcode === 'procedures_prototype' &&
block.mutation.proccode === name) { 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; 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 * Block management: create blocks and scripts from a `create` event
* @param {!object} block Blockly create event to be processed * @param {!object} block Blockly create event to be processed
@ -289,6 +346,8 @@ class Blocks {
if (block.topLevel) { if (block.topLevel) {
this._addScript(block.id); this._addScript(block.id);
} }
this.resetCache();
} }
/** /**
@ -301,7 +360,6 @@ class Blocks {
if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return; if (['field', 'mutation', 'checkbox'].indexOf(args.element) === -1) return;
const block = this._blocks[args.id]; const block = this._blocks[args.id];
if (typeof block === 'undefined') return; if (typeof block === 'undefined') return;
const wasMonitored = block.isMonitored; const wasMonitored = block.isMonitored;
switch (args.element) { switch (args.element) {
case 'field': case 'field':
@ -337,6 +395,8 @@ class Blocks {
} }
break; break;
} }
this.resetCache();
} }
/** /**
@ -393,6 +453,7 @@ class Blocks {
} }
this._blocks[e.id].parent = e.newParent; this._blocks[e.id].parent = e.newParent;
} }
this.resetCache();
} }
@ -447,6 +508,8 @@ class Blocks {
// Delete block itself. // Delete block itself.
delete this._blocks[blockId]; delete this._blocks[blockId];
this.resetCache();
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------