Skip to content

Commit

Permalink
Continued performance refactoring (#7).
Browse files Browse the repository at this point in the history
  • Loading branch information
hexus committed Feb 9, 2019
1 parent d88acf2 commit 55231ba
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 62 deletions.
4 changes: 2 additions & 2 deletions build/index.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions build/old.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions build/pragma.js

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions src/functions/traverseTree.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import isFunction from 'lodash/isFunction';

/**
* Traverse a tree.
*
* TODO: Visitor object? Could have multiple pre/post callbacks
* TODO: Visitor object? Could have multiple pre/post callbacks.
*
* Traversal of children can be halted by returning false from the pre-order
* operation function.
Expand All @@ -17,7 +19,7 @@ function traverseTree(node, pre = null, post = null) {

let result;

if (typeof pre === 'function') {
if (isFunction(pre)) {
result = pre(node);

if (result === false) {
Expand All @@ -31,12 +33,8 @@ function traverseTree(node, pre = null, post = null) {
traverseTree(children[i], pre, post);
}

if (typeof post === 'function') {
result = post(node);

if (result === false) {
return;
}
if (isFunction(post)) {
post(node);
}
}

Expand Down
109 changes: 61 additions & 48 deletions src/services/FormProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ export default class FormProcessor
this.tree = this.buildTree(this.dictionary);

// Clear all caches
this.valueCache = {};
this.valueCache = {};
//this.expressionCache = {};
this.expressionDependencies = {};
}
Expand Down Expand Up @@ -902,15 +902,15 @@ export default class FormProcessor
*/
diffFormData(data)
{
console.time('buildData(this.tree)');
//console.time('buildData(this.tree)');
let formData = this.buildData(this.tree);
console.timeEnd('buildData(this.tree)');
//console.timeEnd('buildData(this.tree)');

//console.log(formData);

console.time('detailedDiff');
//console.time('detailedDiff');
let diff = detailedDiff(formData, data);
console.timeEnd('detailedDiff');
//console.timeEnd('detailedDiff');

//console.log(diff);

Expand All @@ -925,54 +925,74 @@ export default class FormProcessor
*/
update(data)
{
//console.time('diffFormData');
//let diff = this.diffFormData(data);
//console.timeEnd('diffFormData');

this.updatePath('', data);
}

/**
* Update the field at the given path.
*
* @param {string} path - The path of the field to update.
* @param {Object} data - The data to update with.
* @param {number} [direction=BOTH] - Update direction (UP: -1, BOTH: 0, DOWN: 1)
* @param {string} path - The path of the field to update.
* @param {Object} data - The data to update with.
* @param {Object} [visited={}] - Map of fields already visited.
*/
updatePath(path, data, direction = BOTH)
updatePath(path, data, visited = {})
{
let field = this.getField(path);

if (!field) {
if (!field || visited[field.path]) {
return;
}

this.clearValueCache(path);

//console.time('diffFormData');
//let diff = this.diffFormData(data);
//console.timeEnd('diffFormData');

// Update the field and its children
console.time('traverseTree');
//console.time('updatePath() ' + path);
traverseTree(
field,
(field) => {
// Pre-order operation
this.updateFieldInheritance(field, data);

// TODO: Skip fields that have already been visited

// Skip omitted fields
// Skip omitted fields and their children
return !field.omit;
},
(field) => {
// Post-order operation
// Update the current field and its dependencies
//console.log('updatePath() post', field.path);

// Skip fields that have already been visited
if (visited[field.path]) {
//console.warn('skipped visited field', field.path);
return;
}

// if (field.path &&
// (
// !has(diff.added, field.path) &&
// !has(diff.updated, field.path) &&
// !has(diff.deleted, field.path)
// )
// ) {
// return;
// }

this.applyDefaults([field]);

this.updateDataValue(field, data);

this.updateFieldValue(field, data);

this.updateFieldDependencies(field, data, visited);

visited[field.path] = true;
}
);
console.timeEnd('traverseTree');
//console.timeEnd('updatePath() ' + path);

// TODO: Update parent fields and their dependencies
}
Expand All @@ -986,16 +1006,15 @@ export default class FormProcessor
* @protected
* @param {Field[]} fields - The fields to update.
* @param {Object} data - The data to update with.
* @param {number} [direction=BOTH] - Update direction (UP: -1, BOTH: 0, DOWN: 1)
*/
updateFields(fields, data, direction)
updateFields(fields, data)
{
if (!Array.isArray(fields) || !fields.length) {
return;
}

for (let i = 0; i < fields.length; i++) {
this.updatePath(fields[i].path, data, direction);
this.updatePath(fields[i].path, data);
}
}

Expand All @@ -1019,14 +1038,10 @@ export default class FormProcessor
this.clearValueCache(field.path);

// Update the field's children
if (direction >= 0) {
// TODO: This would be a good spot for an event to fire to allow plugins
// (like inheritance) to intercept child update behaviour
this.updateFieldInheritance(field, data);

if (!field.omit) {
//this.updateFields(field.children, data);
}
this.updateFieldInheritance(field, data);

if (!field.omit) {
//this.updateFields(field.children, data);
}

// Apply default values
Expand All @@ -1036,7 +1051,7 @@ export default class FormProcessor
this.updateDataValue(field, data);

// Update the field's value (and update all fields dependent on this one)
this.updateFieldValue(field, data, direction <= 0);
this.updateFieldValue(field, data);
}

/**
Expand All @@ -1062,40 +1077,38 @@ export default class FormProcessor
* Update a field using the given data.
*
* @protected
* @param {Field} field - The field to update.
* @param {Object} data - The data to update with.
* @param {boolean=false} updateParents - Whether to update the field's parents.
* @param {Field} field - The field to update.
* @param {Object} data - The data to update with.
*/
updateFieldValue(field, data, updateParents = false)
updateFieldValue(field, data)
{
if (!field) {
return;
}

// Update the field value
field.value = get(data, field.path);

// Update all fields dependent on this one
this.updateFieldDependencies(field, data, updateParents);
}

/**
* Update fields that are dependent upon the value of the given field.
*
* @protected
* @param {Field} field - The field to update dependencies of.
* @param {Object} data - The data to update from.
* @param {boolean=false} updateAncestors - Whether to update the field's ancestors.
* @param {Field} field - The field to update dependencies of.
* @param {Object} data - The data to update from.
* @param {Object} [visited={}] - Map of fields already visited.
*/
updateFieldDependencies(field, data, updateAncestors)
updateFieldDependencies(field, data, visited = {})
{
// Recursively update parent field values
if (updateAncestors) {
this.updateFieldAncestorValues(field, data);
}
// Update parent field values
this.updateFieldAncestorValues(field, data);

// Update fields listed as dependencies
//this.updateFields(this.getFieldExpressionDependencies(field), data);
// Update the field's expression dependencies
let dependencies = this.getFieldExpressionDependencies(field);

for (let i = 0; i < dependencies.length; i++) {
this.updatePath(dependencies[i].path, data, visited);
}
}

/**
Expand Down

0 comments on commit 55231ba

Please sign in to comment.