forked from alfa-laboratory/arui-feather
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathperformance.js
107 lines (91 loc) · 4.02 KB
/
performance.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Функции проверки равенства двух объектов.
*
* @param {*} objA Первый объект
* @param {*} objB Второй объект
* @param {Boolean} [deep=false] Запускать ли глубокую проверку равенства
* @returns {Boolean}
*/
export function isEqual(objA, objB, deep = false) {
if (Object.is(objA, objB)) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
if (objA.prototype !== objB.prototype) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
const bHasOwnProperty = hasOwnProperty.bind(objB);
while (keysA.length > 0) {
const key = keysA.pop();
if (!bHasOwnProperty(key)) {
return false;
}
const a = objA[key];
const b = objB[key];
if (!Object.is(a, b)) {
if (!deep || typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
return false;
}
if (!isEqual(a, b, deep)) {
return false;
}
}
}
return true;
}
/**
* "Поверхностная" проверка равенства props и state компонента.
*
* @param {*} nextProps next component props
* @param {*} nextState next component state
* @param {*} nextContext next component context
* @returns {Boolean}
*/
function shallow(nextProps, nextState, nextContext) {
return !isEqual(this.props, nextProps)
|| !isEqual(this.state, nextState)
|| !isEqual(this.context, nextContext);
}
/**
* Запускает глубокую проверку равенства props и state компонента.
* Глубокая проверка менее производительна, но позволяет проверять равенство массивов и объектов.
*
* @param {*} nextProps next component props
* @param {*} nextState next component state
* @param {*} nextContext next component context
* @returns {Boolean}
*/
function deep(nextProps, nextState, nextContext) {
return !isEqual(this.props, nextProps, true)
|| !isEqual(this.state, nextState, true)
|| !isEqual(this.context, nextContext, true);
}
/**
* Декоратор для улучшения производительности React компонентов. Работает за счет реализации метода
* [shouldComponentUpdate](https://facebook.github.io/react/docs/advanced-performance.html#avoiding-reconciling-the-dom).
*
* У декоратора есть два режима работы - глубокая и "поверхностная" проверка. В случае, если все props и state
* компонента состоит только из примитивных значений (`number`, `string`, `null`, `undefined`) стоит использовать
* поверхностную проверку, которая будет проверять простое равенство значений в `props` и `state`.
* В случае, если props или state компонентов имеют сложную структуру (массивы, объекты) необходимо использовать
* глубокую проверку.
*
* @param {Boolean} [useDeep=false] Использовать глубокую проверку равенства
* @returns {Function}
*/
export default function performance(useDeep = false) {
return function (target) {
target.prototype.shouldComponentUpdate = useDeep ? deep : shallow;
};
}