@@ -763,10 +763,13 @@ var observerState = {
763
763
* object's property keys into getter/setters that
764
764
* collect dependencies and dispatches updates.
765
765
*/
766
- var Observer = function Observer ( value ) {
766
+ var Observer = function Observer ( value , key ) {
767
767
this . value = value ;
768
768
this . dep = new Dep ( ) ;
769
769
this . vmCount = 0 ;
770
+ if ( key ) {
771
+ this . key = key ;
772
+ }
770
773
def ( value , '__ob__' , this ) ;
771
774
if ( Array . isArray ( value ) ) {
772
775
var augment = hasProto
@@ -829,7 +832,7 @@ function copyAugment (target, src, keys) {
829
832
* returns the new observer if successfully observed,
830
833
* or the existing observer if the value already has one.
831
834
*/
832
- function observe ( value , asRootData ) {
835
+ function observe ( value , asRootData , key ) {
833
836
if ( ! isObject ( value ) ) {
834
837
return
835
838
}
@@ -843,7 +846,9 @@ function observe (value, asRootData) {
843
846
Object . isExtensible ( value ) &&
844
847
! value . _isVue
845
848
) {
846
- ob = new Observer ( value ) ;
849
+ ob = new Observer ( value , key ) ;
850
+ ob . __keyPath = ob . __keyPath ? ob . __keyPath : { } ;
851
+ ob . __keyPath [ key ] = true ;
847
852
}
848
853
if ( asRootData && ob ) {
849
854
ob . vmCount ++ ;
@@ -868,11 +873,13 @@ function defineReactive$$1 (
868
873
return
869
874
}
870
875
876
+ // TODO: 先试验标记一下 keyPath
877
+
871
878
// cater for pre-defined getter/setters
872
879
var getter = property && property . get ;
873
880
var setter = property && property . set ;
874
881
875
- var childOb = ! shallow && observe ( val ) ;
882
+ var childOb = ! shallow && observe ( val , undefined , key ) ;
876
883
Object . defineProperty ( obj , key , {
877
884
enumerable : true ,
878
885
configurable : true ,
@@ -895,6 +902,7 @@ function defineReactive$$1 (
895
902
if ( newVal === value || ( newVal !== newVal && value !== value ) ) {
896
903
return
897
904
}
905
+
898
906
/* eslint-enable no-self-compare */
899
907
if ( "production" !== 'production' && customSetter ) {
900
908
customSetter ( ) ;
@@ -904,8 +912,10 @@ function defineReactive$$1 (
904
912
} else {
905
913
val = newVal ;
906
914
}
907
- childOb = ! shallow && observe ( newVal ) ;
915
+ childOb = ! shallow && observe ( newVal , undefined , key ) ;
908
916
dep . notify ( ) ;
917
+ obj . __keyPath = obj . __keyPath ? obj . __keyPath : { } ;
918
+ obj . __keyPath [ key ] = true ;
909
919
}
910
920
} ) ;
911
921
}
@@ -938,6 +948,9 @@ function set (target, key, val) {
938
948
return val
939
949
}
940
950
defineReactive$$1 ( ob . value , key , val ) ;
951
+ // Vue.set 添加对象属性,渲染时候把val传给小程序渲染
952
+ target . __keyPath = target . __keyPath ? target . __keyPath : { } ;
953
+ target . __keyPath [ key ] = true ;
941
954
ob . dep . notify ( ) ;
942
955
return val
943
956
}
@@ -965,6 +978,9 @@ function del (target, key) {
965
978
if ( ! ob ) {
966
979
return
967
980
}
981
+ target . __keyPath = target . __keyPath ? target . __keyPath : { } ;
982
+ // Vue.del 删除对象属性,渲染时候把这个属性设置为undefined
983
+ target . __keyPath [ key ] = 'del' ;
968
984
ob . dep . notify ( ) ;
969
985
}
970
986
@@ -5293,6 +5309,182 @@ function initMP (mpType, next) {
5293
5309
}
5294
5310
}
5295
5311
5312
+ var updateDataTotal = 0 ; // 总共更新的数据量
5313
+ function diffLog ( updateData ) {
5314
+ updateData = JSON . stringify ( updateData ) ;
5315
+ if ( ! Vue$3 . _mpvueTraceTimer ) {
5316
+ Vue$3 . _mpvueTraceTimer = setTimeout ( function ( ) {
5317
+ clearTimeout ( Vue$3 . _mpvueTraceTimer ) ;
5318
+ updateDataTotal = ( updateDataTotal / 1024 ) . toFixed ( 1 ) ;
5319
+ console . log ( '这次操作引发500ms内数据更新量:' + updateDataTotal + 'kb' ) ;
5320
+ Vue$3 . _mpvueTraceTimer = 0 ;
5321
+ updateDataTotal = 0 ;
5322
+ } , 500 ) ;
5323
+ } else if ( Vue$3 . _mpvueTraceTimer ) {
5324
+ updateData = updateData . replace ( / [ ^ \u0000 - \u00ff ] / g, 'aa' ) ; // 中文占2字节,中文替换成两个字母计算占用空间
5325
+ updateDataTotal += updateData . length ;
5326
+ }
5327
+ }
5328
+
5329
+ function getDeepData ( keyList , viewData ) {
5330
+ if ( keyList . length > 1 ) {
5331
+ var _key = keyList . splice ( 0 , 1 ) ;
5332
+ var _viewData = viewData [ _key ] ;
5333
+ if ( _viewData ) {
5334
+ return getDeepData ( keyList , _viewData )
5335
+ } else {
5336
+ return null
5337
+ }
5338
+ } else {
5339
+ if ( viewData [ keyList [ 0 ] ] ) {
5340
+ return viewData [ keyList [ 0 ] ]
5341
+ } else {
5342
+ return null
5343
+ }
5344
+ }
5345
+ }
5346
+ function compareAndSetDeepData ( key , newData , vm , data ) {
5347
+ // 比较引用类型数据
5348
+ try {
5349
+ var keyList = key . split ( '.' ) ;
5350
+ //page.__viewData__老版小程序不存在,使用mpvue里绑的data比对
5351
+ var oldData = getDeepData ( keyList , vm . $root . $mp . page . data ) ;
5352
+ if ( oldData === null || JSON . stringify ( oldData ) !== JSON . stringify ( newData ) ) {
5353
+ data [ key ] = newData ;
5354
+ }
5355
+ } catch ( e ) {
5356
+ console . log ( e , key , newData , vm ) ;
5357
+ }
5358
+ }
5359
+
5360
+ function cleanKeyPath ( vm ) {
5361
+ if ( vm . __mpKeyPath ) {
5362
+ Object . keys ( vm . __mpKeyPath ) . forEach ( function ( _key ) {
5363
+ delete vm . __mpKeyPath [ _key ] [ '__keyPath' ] ;
5364
+ } ) ;
5365
+ }
5366
+ }
5367
+
5368
+ function minifyDeepData ( rootKey , originKey , vmData , data , _mpValueSet , vm ) {
5369
+ try {
5370
+ if ( vmData instanceof Array ) {
5371
+ // 数组
5372
+ compareAndSetDeepData ( rootKey + '.' + originKey , vmData , vm , data ) ;
5373
+ } else {
5374
+ // Object
5375
+ var _keyPathOnThis = { } ; // 存储这层对象的keyPath
5376
+ if ( vmData . __keyPath ) {
5377
+ // 有更新列表 ,按照更新列表更新
5378
+ _keyPathOnThis = vmData . __keyPath ;
5379
+ Object . keys ( vmData ) . forEach ( function ( _key ) {
5380
+ if ( vmData [ _key ] instanceof Object ) {
5381
+ // 引用类型 递归
5382
+ if ( _key === '__keyPath' ) {
5383
+ return
5384
+ }
5385
+ minifyDeepData ( rootKey + '.' + originKey , _key , vmData [ _key ] , data , null , vm ) ;
5386
+ } else {
5387
+ // 更新列表中的 加入data
5388
+ if ( _keyPathOnThis [ _key ] === true ) {
5389
+ if ( originKey ) {
5390
+ data [ rootKey + '.' + originKey + '.' + _key ] = vmData [ _key ] ;
5391
+ } else {
5392
+ data [ rootKey + '.' + _key ] = vmData [ _key ] ;
5393
+ }
5394
+ }
5395
+ }
5396
+ } ) ;
5397
+ // 根节点可能有父子引用同一个引用类型数据,依赖树都遍历完后清理
5398
+ vm [ '__mpKeyPath' ] = vm [ '__mpKeyPath' ] || { } ;
5399
+ vm [ '__mpKeyPath' ] [ vmData . __ob__ . dep . id ] = vmData ;
5400
+ } else {
5401
+ // 没有更新列表
5402
+ compareAndSetDeepData ( rootKey + '.' + originKey , vmData , vm , data ) ;
5403
+ }
5404
+ }
5405
+ } catch ( e ) {
5406
+ console . log ( e , rootKey , originKey , vmData , data ) ;
5407
+ }
5408
+ }
5409
+
5410
+ function getRootKey ( vm , rootKey ) {
5411
+ if ( ! vm . $parent . $attrs ) {
5412
+ rootKey = '$root.0' + ',' + rootKey ;
5413
+ return rootKey
5414
+ } else {
5415
+ rootKey = vm . $parent . $attrs . mpcomid + ',' + rootKey ;
5416
+ return getRootKey ( vm . $parent , rootKey )
5417
+ }
5418
+ }
5419
+
5420
+ function diffData ( vm , data ) {
5421
+ var vmData = vm . _data || { } ;
5422
+ var vmProps = vm . _props || { } ;
5423
+ var rootKey = '' ;
5424
+ if ( ! vm . $attrs ) {
5425
+ rootKey = '$root.0' ;
5426
+ } else {
5427
+ rootKey = getRootKey ( vm , vm . $attrs . mpcomid ) ;
5428
+ }
5429
+ Vue$3 . nextTick ( function ( ) {
5430
+ cleanKeyPath ( vm ) ;
5431
+ } ) ;
5432
+ // console.log(rootKey)
5433
+
5434
+ // 值类型变量不考虑优化,还是直接更新
5435
+ var __keyPathOnThis = vmData . __keyPath || vm . __keyPath || { } ;
5436
+ delete vm . __keyPath ;
5437
+ delete vmData . __keyPath ;
5438
+ delete vmProps . __keyPath ;
5439
+ if ( vm . _mpValueSet === 'done' ) {
5440
+ // 第二次赋值才进行缩减操作
5441
+ Object . keys ( vmData ) . forEach ( function ( vmDataItemKey ) {
5442
+ if ( vmData [ vmDataItemKey ] instanceof Object ) {
5443
+ // 引用类型
5444
+ if ( vmDataItemKey === '__keyPath' ) { return }
5445
+ minifyDeepData ( rootKey , vmDataItemKey , vmData [ vmDataItemKey ] , data , vm . _mpValueSet , vm ) ;
5446
+ } else if ( vmData [ vmDataItemKey ] !== undefined ) {
5447
+ // _data上的值属性只有要更新的时候才赋值
5448
+ if ( __keyPathOnThis [ vmDataItemKey ] === true ) {
5449
+ data [ rootKey + '.' + vmDataItemKey ] = vmData [ vmDataItemKey ] ;
5450
+ }
5451
+ }
5452
+ } ) ;
5453
+
5454
+ Object . keys ( vmProps ) . forEach ( function ( vmPropsItemKey ) {
5455
+ if ( vmProps [ vmPropsItemKey ] instanceof Object ) {
5456
+ // 引用类型
5457
+ if ( vmPropsItemKey === '__keyPath' ) { return }
5458
+ minifyDeepData ( rootKey , vmPropsItemKey , vmProps [ vmPropsItemKey ] , data , vm . _mpValueSet , vm ) ;
5459
+ } else if ( vmProps [ vmPropsItemKey ] !== undefined ) {
5460
+ data [ rootKey + '.' + vmPropsItemKey ] = vmProps [ vmPropsItemKey ] ;
5461
+ }
5462
+ // _props上的值属性只有要更新的时候才赋值
5463
+ } ) ;
5464
+
5465
+ // 检查完data和props,最后补上_mpProps & _computedWatchers
5466
+ var vmMpProps = vm . _mpProps || { } ;
5467
+ var vmComputedWatchers = vm . _computedWatchers || { } ;
5468
+ Object . keys ( vmMpProps ) . forEach ( function ( mpItemKey ) {
5469
+ data [ rootKey + '.' + mpItemKey ] = vm [ mpItemKey ] ;
5470
+ } ) ;
5471
+ Object . keys ( vmComputedWatchers ) . forEach ( function ( computedItemKey ) {
5472
+ data [ rootKey + '.' + computedItemKey ] = vm [ computedItemKey ] ;
5473
+ } ) ;
5474
+ // 更新的时候要删除$root.0:{},否则会覆盖原正确数据
5475
+ delete data [ rootKey ] ;
5476
+ }
5477
+ if ( vm . _mpValueSet === undefined ) {
5478
+ // 第一次设置数据成功后,标记位置true,再更新到这个节点如果没有keyPath数组认为不需要更新
5479
+ vm . _mpValueSet = 'done' ;
5480
+ }
5481
+ if ( Vue$3 . config . devtools ) {
5482
+ // console.log('更新VM节点', vm)
5483
+ // console.log('实际传到Page.setData数据', data)
5484
+ diffLog ( data ) ;
5485
+ }
5486
+ }
5487
+
5296
5488
// 节流方法,性能优化
5297
5489
// 全局的命名约定,为了节省编译的包大小一律采取形象的缩写,说明如下。
5298
5490
// $c === $child
@@ -5429,6 +5621,8 @@ function getPage (vm) {
5429
5621
return page
5430
5622
}
5431
5623
5624
+ // 优化js变量动态变化时候引起全量更新
5625
+
5432
5626
// 优化每次 setData 都传递大量新数据
5433
5627
function updateDataToMP ( ) {
5434
5628
var page = getPage ( this ) ;
@@ -5437,6 +5631,9 @@ function updateDataToMP () {
5437
5631
}
5438
5632
5439
5633
var data = formatVmData ( this ) ;
5634
+
5635
+ diffData ( this , data ) ;
5636
+
5440
5637
throttleSetData ( page . setData . bind ( page ) , data ) ;
5441
5638
}
5442
5639
0 commit comments