Skip to content

Commit

Permalink
perf(core): optimize diff algorithme to adopt complex production mode…
Browse files Browse the repository at this point in the history
… data
  • Loading branch information
Genuifx committed May 8, 2020
1 parent 6b78b6b commit 16b6293
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 39 deletions.
97 changes: 60 additions & 37 deletions packages/wxa-core/src/diff/flatten.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
// fork from https://github.com/hughsk/flat/blob/master/index.js
// modify for wxa

const getType = (v) => Object.prototype.toString.call(v);

const is = (t, v) => {
return getType(v) === `[object ${t}]`;
};


function flatten(oldValue, newValue, diff, opts) {
// if diff element is an array, then just return the array in wxa. so we allways need safe options in wxa.
opts = opts || {safe: true};
Expand All @@ -10,59 +17,75 @@ function flatten(oldValue, newValue, diff, opts) {
let output = {};

function step(oldValue, newValue, diff, prev, currentDepth) {
currentDepth = currentDepth || 1;
Object.keys(diff).forEach(function(key) {
let diffChildValue = diff[key];
let isDiffChildValueArray = opts.safe && Array.isArray(diffChildValue);

let typeOfDiff = Object.prototype.toString.call(diffChildValue);
let isDiffChildValueObject = (
typeOfDiff === '[object Object]' ||
typeOfDiff === '[object Array]'
);
currentDepth = currentDepth || 1;

let sourceValue;
let newKey;
let newChildValue = newValue[key];
Object.keys(diff).forEach(function(key) {
let diffChildValue = diff[key];
// new child array added
let isDiffChildValueArray =
opts.safe && Array.isArray(diffChildValue);

// Only digits (0-9) can be put inside [] in the path string
newKey = prev ? /^\d+$/.test(key) ? prev + '[' + key + ']' : prev + delimiter + key : key;
let isDiffChildValueObject = is('Object', diffChildValue) || is('Array', diffChildValue);

let newKey;
let newChildValue = newValue[key];
let sourceValue = oldValue ? oldValue[key] : void(0);

if (oldValue) {
// hasValue, meaning that new value still contain old one.
sourceValue = oldValue[key];
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
// array element changed or added.
newKey = prev ? prev + `[${key}]` : key;
} else {
newKey = prev ? prev + delimiter + key : key;
}

// Check Array
if (
(
Array.isArray(sourceValue) ||
(Object.prototype.toString.call(sourceValue) === '[object Object]')
) &&
Object.keys(diffChildValue).some((key)=>diffChildValue[key]===void(0))
(Array.isArray(sourceValue) || is('Object', sourceValue)) &&
Object.keys(diffChildValue).some((key) => diffChildValue[key] === void 0)
) {
// console.log(currentDepth, ' element deleted ', newKey);
// some array or object element have been deleted.
// return new array or object.
output[newKey] = newChildValue;
return;
} else if (Array.isArray(oldValue)) {
// array element changed or added.
newKey = prev ? prev + `[${key}]` : key;
return output[newKey] = newChildValue;
}

if (
!isDiffChildValueObject ||
getType(sourceValue) !== getType(newChildValue)
) {
return output[newKey] = diffChildValue;
}
}

if (!isDiffChildValueArray && isDiffChildValueObject && Object.keys(diffChildValue).length &&
(!opts.maxDepth || currentDepth < maxDepth)) {
return step(sourceValue, newChildValue, diffChildValue, newKey, currentDepth + 1);
}
if (
!isDiffChildValueArray &&
isDiffChildValueObject &&
Object.keys(diffChildValue).length &&
(!opts.maxDepth || currentDepth < maxDepth)
) {
if (
currentDepth < 2 ||
(currentDepth >= 2 && Object.keys(diffChildValue).length <= 4)
) {
// tiny object
// end process go next step
return step(
sourceValue,
newChildValue,
diffChildValue,
newKey,
currentDepth + 1
);
} else {
return output[newKey] = newChildValue;
}
}

output[newKey] = diffChildValue;
});
output[newKey] = diffChildValue;
});
}

step(oldValue, newValue, diff);

return output;
}
}

export default flatten;
12 changes: 12 additions & 0 deletions packages/wxa-core/test/diff/diff.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,16 @@ describe('diff array', ()=>{

expect(pageDiff({x: arr2})).toMatchObject({'x[0]': {a: 1, b: 2}});
});

test('get diff properties', ()=>{
let page = {
data: {
x: arr1,
},
};

let pageDiff = diff.bind(page);

expect(pageDiff({x: [{a: 1, b: 2, c: {a: 1}}]})).toMatchObject({'x[0].c': {a: 1}});
});
});
68 changes: 66 additions & 2 deletions packages/wxa-core/test/diff/flatten.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('flatten object for wxa', ()=>{

expect(flatten(
{
a: 2,
a: {c: {d: 3}},
},
{
a: {c: {d: 1}},
Expand Down Expand Up @@ -76,7 +76,7 @@ describe('flatten object for wxa', ()=>{
'1': {b: 1},
},
},
})).toMatchObject({'a.c[1].b': 1});
})).toMatchObject({'a.c[1]': {'b': 1}});

expect(flatten(
{
Expand Down Expand Up @@ -152,4 +152,68 @@ describe('flatten object for wxa', ()=>{

expect(flatten(oldValue, newValueWithDelete, {school: void(0), fav: {a: void(0), b: 'football'}})).toMatchObject({school: void(0), fav: {b: 'football'}});
});

test('Big Different Object', ()=>{
expect(flatten(
{
user$: {
b: 3,
order: {
c: [1, 2],
d: 1,
e: 2,
f: 3,
d1: 1,
e22: 2,
f2: 4,
},
},
},
{
user$: {
b: 3,
order: {
c: [1, 2],
d: 1,
e: 2,
f: 3,
d1: 1,
e22: 2,
f2: 4,
},
},
},
{
user$: {
b: 4,
order: {
c: [1, 2],
d: 1,
e: 2,
f: 3,
d1: 1,
},
},
}
)).toMatchObject({
'user$.b': 4,
'user$.order': {c: [1, 2], d: 1, e: 2, f: 3, d1: 1, e22: 2, f2: 4},
});
});

test('diff data Array to Object', ()=>{
expect(flatten(
{
user$: {},
},
{
user$: [],
},
{
user$: [],
}
)).toMatchObject({
'user$': [],
});
});
});

0 comments on commit 16b6293

Please sign in to comment.