Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[perf] cache resolved data element options #6579

Merged
merged 3 commits into from Oct 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/controllers/controller.bubble.js
Expand Up @@ -154,6 +154,11 @@ module.exports = DatasetController.extend({
datasetIndex: me.index
};

// In case values were cached (and thus frozen), we need to clone the values
if (me._cachedDataOpts === values) {
values = helpers.extend({}, values);
}

// Custom radius resolution
values.radius = resolve([
custom.radius,
Expand Down
23 changes: 19 additions & 4 deletions src/core/core.datasetController.js
Expand Up @@ -290,6 +290,7 @@ helpers.extend(DatasetController.prototype, {
_update: function(reset) {
var me = this;
me._configure();
me._cachedDataOpts = null;
me.update(reset);
},

Expand Down Expand Up @@ -389,13 +390,16 @@ helpers.extend(DatasetController.prototype, {
*/
_resolveDataElementOptions: function(element, index) {
var me = this;
var custom = element && element.custom;
var cached = me._cachedDataOpts;
if (cached && !custom) {
return cached;
}
var chart = me.chart;
var datasetOpts = me._config;
var custom = element.custom || {};
var options = chart.options.elements[me.dataElementType.prototype._type] || {};
var elementOptions = me._dataElementOptions;
var values = {};
var keys, i, ilen, key;

// Scriptable options
var context = {
Expand All @@ -405,14 +409,21 @@ helpers.extend(DatasetController.prototype, {
datasetIndex: me.index
};

// `resolve` sets cacheable to `false` if any option is indexed or scripted
var info = {cacheable: !custom};

var keys, i, ilen, key;

custom = custom || {};

if (helpers.isArray(elementOptions)) {
for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
key = elementOptions[i];
values[key] = resolve([
custom[key],
datasetOpts[key],
options[key]
], context, index);
], context, index, info);
}
} else {
keys = Object.keys(elementOptions);
Expand All @@ -423,10 +434,14 @@ helpers.extend(DatasetController.prototype, {
datasetOpts[elementOptions[key]],
datasetOpts[key],
options[key]
], context, index);
], context, index, info);
}
}

if (info.cacheable) {
me._cachedDataOpts = Object.freeze(values);
}

return values;
},

Expand Down
10 changes: 9 additions & 1 deletion src/helpers/helpers.options.js
Expand Up @@ -115,9 +115,12 @@ module.exports = {
* is called with `context` as first argument and the result becomes the new input.
* @param {number} [index] - If defined and the current value is an array, the value
* at `index` become the new input.
* @param {object} [info] - object to return information about resolution in
* @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
* @since 2.7.0
*/
resolve: function(inputs, context, index) {
resolve: function(inputs, context, index, info) {
var cacheable = true;
var i, ilen, value;

for (i = 0, ilen = inputs.length; i < ilen; ++i) {
Expand All @@ -127,11 +130,16 @@ module.exports = {
}
if (context !== undefined && typeof value === 'function') {
value = value(context);
cacheable = false;
}
if (index !== undefined && helpers.isArray(value)) {
value = value[index];
cacheable = false;
}
if (value !== undefined) {
if (info && !cacheable) {
info.cacheable = false;
}
return value;
}
}
Expand Down