@feng3d/reactivity 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2019 feng
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2019 feng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,159 +1,159 @@
1
- # @feng3d/reactivity
2
-
3
- feng3d的响应式库,使用方式以及API与@vue/reactivity基本保持一致。
4
-
5
- 源码:https://gitee.com/feng3d/reactivity
6
-
7
- 文档:https://feng3d.com/reactivity
8
-
9
- ## 网站
10
-
11
- https://feng3d.com/reactivity
12
-
13
- ## 安装
14
- ```
15
- npm install @feng3d/reactivity
16
- ```
17
-
18
- ## 快速开始
19
-
20
- ```ts
21
- import { ref, computed } from "@feng3d/reactivity";
22
-
23
- const a = ref(1);
24
- const b = ref(2);
25
- const c = computed(() => a.value + b.value);
26
-
27
- console.log(c.value); // 3
28
- a.value = 3;
29
- console.log(c.value); // 5
30
- ```
31
-
32
- ## 缘由
33
- 在feng3d引擎中使用`@vue/reactivity`代替`@feng3d/watcher`来维护数据驱动功能时发现性能严重下降。
34
-
35
- 为了解决这个问题,我重新实现了一个响应式库,并且在性能上进行了优化。
36
-
37
- ### 问题示例
38
-
39
- 示例: https://feng3d.com/reactivity/#复杂情况取值
40
-
41
- | 运行库 | 性能(ms) | 速度(x) |
42
- | --- | --- | --- |
43
- | @feng3d/reactivity | 2.8 | 286 |
44
- | @vue/reactivity | 801 | 1 |
45
-
46
- ### 测试代码
47
- ```ts
48
- 复杂情况取值(ref, computed, 10000);
49
-
50
- export function 复杂情况取值(ref: <T>(value?: T) => { value: T }, computed: <T>(func: (oldValue?: T) => T) => { readonly value: T }, count: number)
51
- {
52
- const result = { time: undefined, values: [] };
53
-
54
- const b = ref(2);
55
-
56
- function 递归(depth = 10)
57
- {
58
- if (depth <= 0) return computed(() =>
59
- {
60
- return b.value
61
- }).value;
62
-
63
- return computed(() =>
64
- {
65
- return 递归(depth - 1) + 递归(depth - 2);
66
- }).value;
67
- }
68
-
69
- const cb = computed(() =>
70
- {
71
- return 递归(16);
72
- });
73
-
74
- b.value++;
75
- cb.value;
76
-
77
- const start = performance.now();
78
- for (let i = 0; i < count; i++)
79
- {
80
- ref(1).value++; // 添加此行代码将会导致 @vue/reactivity 版本的性能下降,而 @feng3d/reactivity 版本的性能保持不变
81
-
82
- cb.value;
83
- }
84
- result.time = performance.now() - start;
85
-
86
- result.values.push(cb.value);
87
-
88
- return result;
89
- }
90
- ```
91
-
92
- ### 分析
93
- @feng3d/reactivity自下而上的使用脏标记进行维护状态,当发生变化时只会冒泡一次到父节点,全局有变化时(ref(1).value++ 标记变化)并不会触发重新计算。
94
- @vue/reactivity自上而下的使用版本号进行维护状态,当全局有变化时(ref(1).value++ 标记变化)每次取值时都会遍历整个树的子节点比对版本号判断是否需要重新计算。
95
-
96
- ## 性能情况
97
- ### 使用不同方式维护子节点
98
-
99
- // 修改第一个元素 `arr[0].value++;`
100
- | 方式 | 性能(ms) | 速度(x) | 隐患 |
101
- | --- | --- | --- | --- |
102
- | 失效子节点字典 | 126 | 8.8 | 当节点失效时无法完全清除子节点,并且无法保障检查节点的顺序,导致触发过时的依赖性能或许更差,但一般情况性能最佳。 |
103
- | 全量子节点链表 | 679 | 1.6 | 无 |
104
- | 全量子节点字典 | 1110 | 1 | 无 |
105
- | @vue/reactivity | 216 | 5.1 | 无 |
106
-
107
- // 修改最后一个元素 `arr[9999].value++`
108
- | 方式 | 性能(ms) | 速度(x) | 隐患 |
109
- | --- | --- | --- | --- |
110
- | 失效子节点字典 | 125 | 9.68 | 当节点失效时无法完全清除子节点,并且无法保障检查节点的顺序,导致触发过时的依赖性能或许更差,但一般情况性能最佳。 |
111
- | 全量子节点链表 | 730 | 1.65 | 无 |
112
- | 全量子节点字典 | 1210 | 1 | 无 |
113
- | @vue/reactivity | 253 | 4.78 | 无 |
114
-
115
- ```ts
116
- import { computed, ref } from "@feng3d/reactivity";
117
-
118
- 数组取值(ref, computed, 1000)
119
-
120
- export function 数组取值(ref: <T>(value?: T) => { value: T }, computed: <T>(func: (oldValue?: T) => T) => { readonly value: T },count: number)
121
- {
122
- const result = { time: undefined, values: [] };
123
-
124
- const arr:{
125
- value: number;
126
- }[] = new Array(10000).fill(0).map(() => ref(0));
127
-
128
- const cb = computed(() =>
129
- {
130
- return arr.reduce((prev, curr) => prev + curr.value, 0);
131
- });
132
-
133
- const start = performance.now();
134
- for (let i = 0; i < count; i++)
135
- {
136
- // arr[0].value++; // 修改第一个元素
137
- arr[9999].value++; // 修改最后一个元素
138
- cb.value;
139
- }
140
- result.time = performance.now() - start;
141
-
142
- result.values.push(cb.value);
143
-
144
- return result;
145
- }
146
-
147
- ```
148
-
149
- ## 为了库的简单易用性不支持以下内容
150
- - markRaw
151
- - shallowRef
152
- - shallowReactive
153
- - shallowReadonly
154
- - readonly
155
- - computed 中 setter
156
- - __v_skip
157
-
158
- ## 扩展
1
+ # @feng3d/reactivity
2
+
3
+ feng3d的响应式库,使用方式以及API与@vue/reactivity基本保持一致。
4
+
5
+ 源码:https://gitee.com/feng3d/reactivity
6
+
7
+ 文档:https://feng3d.com/reactivity
8
+
9
+ ## 网站
10
+
11
+ https://feng3d.com/reactivity
12
+
13
+ ## 安装
14
+ ```
15
+ npm install @feng3d/reactivity
16
+ ```
17
+
18
+ ## 快速开始
19
+
20
+ ```ts
21
+ import { ref, computed } from "@feng3d/reactivity";
22
+
23
+ const a = ref(1);
24
+ const b = ref(2);
25
+ const c = computed(() => a.value + b.value);
26
+
27
+ console.log(c.value); // 3
28
+ a.value = 3;
29
+ console.log(c.value); // 5
30
+ ```
31
+
32
+ ## 缘由
33
+ 在feng3d引擎中使用`@vue/reactivity`代替`@feng3d/watcher`来维护数据驱动功能时发现性能严重下降。
34
+
35
+ 为了解决这个问题,我重新实现了一个响应式库,并且在性能上进行了优化。
36
+
37
+ ### 问题示例
38
+
39
+ 示例: https://feng3d.com/reactivity/#复杂情况取值
40
+
41
+ | 运行库 | 性能(ms) | 速度(x) |
42
+ | --- | --- | --- |
43
+ | @feng3d/reactivity | 2.8 | 286 |
44
+ | @vue/reactivity | 801 | 1 |
45
+
46
+ ### 测试代码
47
+ ```ts
48
+ 复杂情况取值(ref, computed, 10000);
49
+
50
+ export function 复杂情况取值(ref: <T>(value?: T) => { value: T }, computed: <T>(func: (oldValue?: T) => T) => { readonly value: T }, count: number)
51
+ {
52
+ const result = { time: undefined, values: [] };
53
+
54
+ const b = ref(2);
55
+
56
+ function 递归(depth = 10)
57
+ {
58
+ if (depth <= 0) return computed(() =>
59
+ {
60
+ return b.value
61
+ }).value;
62
+
63
+ return computed(() =>
64
+ {
65
+ return 递归(depth - 1) + 递归(depth - 2);
66
+ }).value;
67
+ }
68
+
69
+ const cb = computed(() =>
70
+ {
71
+ return 递归(16);
72
+ });
73
+
74
+ b.value++;
75
+ cb.value;
76
+
77
+ const start = performance.now();
78
+ for (let i = 0; i < count; i++)
79
+ {
80
+ ref(1).value++; // 添加此行代码将会导致 @vue/reactivity 版本的性能下降,而 @feng3d/reactivity 版本的性能保持不变
81
+
82
+ cb.value;
83
+ }
84
+ result.time = performance.now() - start;
85
+
86
+ result.values.push(cb.value);
87
+
88
+ return result;
89
+ }
90
+ ```
91
+
92
+ ### 分析
93
+ @feng3d/reactivity自下而上的使用脏标记进行维护状态,当发生变化时只会冒泡一次到父节点,全局有变化时(ref(1).value++ 标记变化)并不会触发重新计算。
94
+ @vue/reactivity自上而下的使用版本号进行维护状态,当全局有变化时(ref(1).value++ 标记变化)每次取值时都会遍历整个树的子节点比对版本号判断是否需要重新计算。
95
+
96
+ ## 性能情况
97
+ ### 使用不同方式维护子节点
98
+
99
+ // 修改第一个元素 `arr[0].value++;`
100
+ | 方式 | 性能(ms) | 速度(x) | 隐患 |
101
+ | --- | --- | --- | --- |
102
+ | 失效子节点字典 | 126 | 8.8 | 当节点失效时无法完全清除子节点,并且无法保障检查节点的顺序,导致触发过时的依赖性能或许更差,但一般情况性能最佳。 |
103
+ | 全量子节点链表 | 679 | 1.6 | 无 |
104
+ | 全量子节点字典 | 1110 | 1 | 无 |
105
+ | @vue/reactivity | 216 | 5.1 | 无 |
106
+
107
+ // 修改最后一个元素 `arr[9999].value++`
108
+ | 方式 | 性能(ms) | 速度(x) | 隐患 |
109
+ | --- | --- | --- | --- |
110
+ | 失效子节点字典 | 125 | 9.68 | 当节点失效时无法完全清除子节点,并且无法保障检查节点的顺序,导致触发过时的依赖性能或许更差,但一般情况性能最佳。 |
111
+ | 全量子节点链表 | 730 | 1.65 | 无 |
112
+ | 全量子节点字典 | 1210 | 1 | 无 |
113
+ | @vue/reactivity | 253 | 4.78 | 无 |
114
+
115
+ ```ts
116
+ import { computed, ref } from "@feng3d/reactivity";
117
+
118
+ 数组取值(ref, computed, 1000)
119
+
120
+ export function 数组取值(ref: <T>(value?: T) => { value: T }, computed: <T>(func: (oldValue?: T) => T) => { readonly value: T },count: number)
121
+ {
122
+ const result = { time: undefined, values: [] };
123
+
124
+ const arr:{
125
+ value: number;
126
+ }[] = new Array(10000).fill(0).map(() => ref(0));
127
+
128
+ const cb = computed(() =>
129
+ {
130
+ return arr.reduce((prev, curr) => prev + curr.value, 0);
131
+ });
132
+
133
+ const start = performance.now();
134
+ for (let i = 0; i < count; i++)
135
+ {
136
+ // arr[0].value++; // 修改第一个元素
137
+ arr[9999].value++; // 修改最后一个元素
138
+ cb.value;
139
+ }
140
+ result.time = performance.now() - start;
141
+
142
+ result.values.push(cb.value);
143
+
144
+ return result;
145
+ }
146
+
147
+ ```
148
+
149
+ ## 为了库的简单易用性不支持以下内容
150
+ - markRaw
151
+ - shallowRef
152
+ - shallowReactive
153
+ - shallowReadonly
154
+ - readonly
155
+ - computed 中 setter
156
+ - __v_skip
157
+
158
+ ## 扩展
159
159
  - 扩大被反应式的对象的类型范围,只有`Object.isExtensible`不通过的对象不被响应化。Float32Array等都允许被响应化。
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ class Reactivity {
17
17
  * 建立与父节点的依赖关系。
18
18
  */
19
19
  track() {
20
- if (!_shouldTrack)
20
+ if (!Reactivity.activeReactivity || !_shouldTrack)
21
21
  return;
22
22
  const parent = Reactivity.activeReactivity;
23
23
  if (parent) {
@@ -107,13 +107,16 @@ class ComputedReactivity extends Reactivity {
107
107
  this._func = func;
108
108
  }
109
109
  /**
110
- * 捕捉。
110
+ * 获取值。
111
111
  *
112
- * 建立与父节点的依赖关系。
112
+ * 取值时将会建立与父节点的依赖关系。
113
+ *
114
+ * 同时会检查子节点是否发生变化,如果发生变化,则重新计算。
113
115
  */
114
- track() {
116
+ get value() {
115
117
  this.runIfDirty();
116
- super.track();
118
+ this.track();
119
+ return this._value;
117
120
  }
118
121
  /**
119
122
  * 触发。
@@ -355,6 +358,8 @@ class PropertyReactivity extends Reactivity {
355
358
  * @returns
356
359
  */
357
360
  static track(target, type, key) {
361
+ if (!Reactivity.activeReactivity)
362
+ return;
358
363
  const dep = property(target, key);
359
364
  dep.track();
360
365
  }