@feng3d/reactivity 1.0.8 → 1.0.11
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 +15 -21
- package/README.md +158 -158
- package/dist/index.js +208 -46
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +209 -47
- package/dist/index.umd.cjs.map +1 -1
- package/lib/arrayInstrumentations.d.ts.map +1 -1
- package/lib/batch.d.ts.map +1 -1
- package/lib/effectScope.d.ts.map +1 -1
- package/package.json +76 -69
- package/src/ReactiveObject.ts +130 -130
- package/src/Reactivity.ts +168 -168
- package/src/arrayInstrumentations.ts +799 -801
- package/src/baseHandlers.ts +312 -312
- package/src/batch.ts +130 -134
- package/src/collectionHandlers.ts +486 -486
- package/src/computed.ts +253 -253
- package/src/effect.ts +146 -146
- package/src/effectScope.ts +293 -294
- package/src/index.ts +9 -10
- package/src/property.ts +231 -231
- package/src/reactive.ts +186 -186
- package/src/ref.ts +150 -150
- package/src/shared/constants.ts +41 -41
- package/src/shared/general.ts +109 -109
- package/tsconfig.json +21 -20
package/LICENSE
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
MIT
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 许可证
|
|
2
|
+
|
|
3
|
+
版权所有 (c) 2026 feng
|
|
4
|
+
|
|
5
|
+
特此授予任何获得本软件及相关文档文件("软件")副本的人免费许可,
|
|
6
|
+
可以不受限制地处理本软件,包括但不限于使用、复制、修改、合并、
|
|
7
|
+
发布、分发、再许可和/或销售本软件的副本,并允许向其提供本软件的
|
|
8
|
+
人这样做,但须符合以下条件:
|
|
9
|
+
|
|
10
|
+
上述版权声明和本许可声明应包含在本软件的所有副本或主要部分中。
|
|
11
|
+
|
|
12
|
+
本软件按"原样"提供,不提供任何明示或暗示的保证,包括但不限于对
|
|
13
|
+
适销性、特定用途适用性和非侵权性的保证。在任何情况下,作者或版权
|
|
14
|
+
持有人均不对因本软件或本软件的使用或其他交易而产生的任何索赔、
|
|
15
|
+
损害或其他责任负责,无论是在合同诉讼、侵权诉讼还是其他诉讼中。
|
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等都允许被响应化。
|