1
+ import { isObject , isArray , hasOwn , isIntegerKey } from './shared.js'
2
+
3
+ const proxyMap = new WeakMap ( ) ;
4
+ const targetMap = new WeakMap ( ) ;
5
+ const ITERATE_KEY = Symbol ( ) ;
6
+
7
+ let viewEffect ;
8
+
9
+ export const setViewEffect = ( fn ) => {
10
+ viewEffect = fn ;
11
+ fn ( ) ;
12
+ }
13
+
14
+ export function reactive ( target ) {
15
+ const existingProxy = proxyMap . get ( target ) ;
16
+ if ( existingProxy ) {
17
+ return existingProxy
18
+ }
19
+
20
+ const proxy = new Proxy (
21
+ target ,
22
+ baseHandlers
23
+ ) ;
24
+
25
+ proxyMap . set ( target , proxy ) ;
26
+ return proxy
27
+ }
28
+
29
+ // 新增,用于暂停/恢复 track 能力
30
+ export let shouldTrack = true ;
31
+ const trackStack = [ ] ;
32
+
33
+ export function pauseTracking ( ) {
34
+ trackStack . push ( shouldTrack )
35
+ shouldTrack = false
36
+ }
37
+
38
+ export function resetTracking ( ) {
39
+ const last = trackStack . pop ( )
40
+ shouldTrack = last === undefined ? true : last
41
+ }
42
+
43
+ // 新增,解决递归追踪的问题
44
+ function createArrayInstrumentations ( target ) {
45
+ const instrumentations = { } ;
46
+ [ 'push' , 'pop' , 'shift' , 'unshift' , 'splice' ] . forEach ( key => {
47
+ instrumentations [ key ] = function ( ...args ) {
48
+ pauseTracking ( ) ; // 暂停 track
49
+ const res = target [ key ] . apply ( this , args ) ;
50
+ resetTracking ( ) ; // 恢复 track
51
+ return res
52
+ }
53
+ } )
54
+ return instrumentations
55
+ }
56
+
57
+ const baseHandlers = {
58
+ get ( target , key , receiver ) {
59
+ // 新增,解决递归追踪的问题
60
+ const targetIsArray = isArray ( target ) ;
61
+ const arrayInstrumentations = createArrayInstrumentations ( target ) ;
62
+ if ( targetIsArray && hasOwn ( arrayInstrumentations , key ) ) {
63
+ return Reflect . get ( arrayInstrumentations , key , receiver )
64
+ }
65
+
66
+ const res = Reflect . get ( target , key , receiver ) ;
67
+ track ( target , key ) ;
68
+
69
+ if ( isObject ( res ) ) {
70
+ return reactive ( res ) ;
71
+ }
72
+
73
+ return res ;
74
+ } ,
75
+ set ( target , key , value , receiver ) {
76
+ const hadKey = isArray ( target ) && isIntegerKey ( key )
77
+ ? Number ( key ) < target . length
78
+ : hasOwn ( target , key ) ;
79
+
80
+ const res = Reflect . set ( target , key , value , receiver ) ;
81
+ trigger ( target , key , hadKey ? 'set' : 'add' , value ) ;
82
+ return res ;
83
+ } ,
84
+ has ( target , key ) {
85
+ const res = Reflect . has ( target , key ) ;
86
+ track ( target , key ) ;
87
+ return res ;
88
+ } ,
89
+ ownKeys ( target ) {
90
+ const key = isArray ( target ) ? 'length' : ITERATE_KEY ;
91
+ track ( target , key ) ;
92
+ return Reflect . ownKeys ( target ) ;
93
+ } ,
94
+ deleteProperty ( target , key ) {
95
+ const hadKey = hasOwn ( target , key ) ;
96
+ const res = Reflect . deleteProperty ( target , key ) ;
97
+ if ( res && hadKey ) {
98
+ trigger ( target , key , 'delete' ) ;
99
+ }
100
+ return res
101
+ }
102
+ }
103
+
104
+ const track = ( target , key ) => {
105
+ if ( ! shouldTrack || ! viewEffect ) return ; // 新增
106
+ let depsMap = targetMap . get ( target )
107
+ if ( ! depsMap ) {
108
+ targetMap . set ( target , ( depsMap = new Map ( ) ) )
109
+ }
110
+ let dep = depsMap . get ( key )
111
+ if ( ! dep ) {
112
+ depsMap . set ( key , ( dep = new Set ( ) ) ) ;
113
+ dep . add ( viewEffect ) ;
114
+ }
115
+ }
116
+
117
+ const trigger = ( target , key , type , newValue ) => {
118
+ const depsMap = targetMap . get ( target ) ;
119
+ if ( ! depsMap ) {
120
+ return
121
+ }
122
+
123
+ let deps = [ ] ;
124
+
125
+ if ( key === 'length' && isArray ( target ) ) {
126
+ depsMap . forEach ( ( dep , key ) => {
127
+ if ( key === 'length' || key >= newValue ) {
128
+ deps . push ( dep )
129
+ }
130
+ } )
131
+ } else {
132
+ if ( key !== void 0 ) {
133
+ deps . push ( depsMap . get ( key ) ) ;
134
+ }
135
+
136
+ switch ( type ) {
137
+ case 'add' :
138
+ if ( ! isArray ( target ) ) {
139
+ deps . push ( depsMap . get ( ITERATE_KEY ) ) ;
140
+ } else if ( isIntegerKey ( key ) ) {
141
+ deps . push ( depsMap . get ( 'length' ) )
142
+ }
143
+ break ;
144
+ case 'delete' :
145
+ if ( ! isArray ( target ) ) {
146
+ deps . push ( depsMap . get ( ITERATE_KEY ) ) ;
147
+ }
148
+ break ;
149
+ }
150
+ }
151
+
152
+ let viewEffects = [ ] ;
153
+ for ( const dep of deps ) {
154
+ if ( dep ) {
155
+ viewEffects . push ( ...dep )
156
+ }
157
+ }
158
+
159
+ viewEffects = new Set ( viewEffects ) ;
160
+
161
+ viewEffects . forEach ( effectFn => {
162
+ effectFn && effectFn ( )
163
+ } ) ;
164
+ }
0 commit comments