@@ -757,3 +757,207 @@ test('avoid unnecessary reaction', () => {
757
757
758
758
expect ( fn1 ) . toBeCalledTimes ( 1 )
759
759
} )
760
+
761
+ test ( 'avoid missing reaction' , ( ) => {
762
+ const obs = observable < any > ( {
763
+ res : 0 ,
764
+ } )
765
+
766
+ const fn1 = jest . fn ( )
767
+ const fn2 = jest . fn ( )
768
+
769
+ let value
770
+ autorun ( ( ) => {
771
+ fn1 ( )
772
+ value = obs . res
773
+ } )
774
+
775
+ autorun ( ( ) => {
776
+ fn2 ( )
777
+ obs . res
778
+ if ( obs . res !== 0 ) obs . res = obs . res + 1
779
+ } )
780
+
781
+ expect ( value ) . toBe ( 0 )
782
+
783
+ obs . res = 1
784
+
785
+ expect ( value ) . toBe ( 2 )
786
+
787
+ expect ( fn1 ) . toBeCalledTimes ( 3 )
788
+ expect ( fn2 ) . toBeCalledTimes ( 2 )
789
+ } )
790
+
791
+ test ( 'avoid reaction twice' , ( ) => {
792
+ const obs = observable < any > ( {
793
+ res : 0 ,
794
+ } )
795
+
796
+ const fn1 = jest . fn ( )
797
+ const fn2 = jest . fn ( )
798
+
799
+ let value
800
+ autorun ( ( ) => {
801
+ fn1 ( )
802
+ obs . res
803
+ if ( obs . res !== 0 ) obs . res = obs . res + 1
804
+ } )
805
+
806
+ autorun ( ( ) => {
807
+ fn2 ( )
808
+ value = obs . res
809
+ } )
810
+
811
+ expect ( value ) . toBe ( 0 )
812
+
813
+ obs . res = 1
814
+
815
+ expect ( value ) . toBe ( 2 )
816
+ expect ( fn1 ) . toBeCalledTimes ( 2 )
817
+ expect ( fn2 ) . toBeCalledTimes ( 2 )
818
+ } )
819
+
820
+ test ( 'computed reaction' , ( ) => {
821
+ const obs = observable < any > ( {
822
+ aa : 1 ,
823
+ bb : 1 ,
824
+ } )
825
+
826
+ const computed = observable . computed ( ( ) => {
827
+ return obs . aa + obs . bb
828
+ } )
829
+
830
+ autorun ( ( ) => {
831
+ if ( obs . bb === 3 ) {
832
+ obs . aa = 3
833
+ }
834
+ } )
835
+
836
+ batch ( ( ) => {
837
+ obs . aa = 2 // 会触发 computed 发生变化
838
+
839
+ obs . bb = 3
840
+ } )
841
+
842
+ expect ( computed . value ) . toBe ( 6 )
843
+ } )
844
+
845
+ test ( 'accurate boundary' , ( ) => {
846
+ const obs = observable < any > ( {
847
+ a : '' ,
848
+ b : '' ,
849
+ c : '' ,
850
+ } )
851
+
852
+ autorun ( ( ) => {
853
+ obs . c = obs . a + obs . b
854
+ } )
855
+
856
+ autorun ( ( ) => {
857
+ obs . b = obs . a
858
+ } )
859
+
860
+ obs . a = 'a'
861
+ expect ( obs . a ) . toBe ( 'a' )
862
+ expect ( obs . b ) . toBe ( 'a' )
863
+ expect ( obs . c ) . toBe ( 'aa' )
864
+ } )
865
+
866
+ test ( 'multiple source update' , ( ) => {
867
+ const obs = observable < any > ( { } )
868
+
869
+ const fn1 = jest . fn ( )
870
+ const fn2 = jest . fn ( )
871
+
872
+ autorun ( ( ) => {
873
+ const A = obs . A
874
+ const B = obs . B
875
+ if ( A !== undefined && B !== undefined ) {
876
+ obs . C = A / B
877
+ fn1 ( )
878
+ }
879
+ } )
880
+
881
+ autorun ( ( ) => {
882
+ const C = obs . C
883
+ const B = obs . B
884
+ if ( C !== undefined && B !== undefined ) {
885
+ obs . D = C * B
886
+ fn2 ( )
887
+ }
888
+ } )
889
+
890
+ obs . A = 1
891
+ obs . B = 2
892
+
893
+ expect ( fn1 ) . toBeCalledTimes ( 1 )
894
+ expect ( fn2 ) . toBeCalledTimes ( 1 )
895
+ } )
896
+
897
+ test ( 'same source in nest update' , ( ) => {
898
+ const obs = observable < any > ( { } )
899
+
900
+ const fn1 = jest . fn ( )
901
+
902
+ autorun ( ( ) => {
903
+ const B = obs . B
904
+ obs . B = 'B'
905
+ fn1 ( )
906
+ return B
907
+ } )
908
+
909
+ obs . B = 'B2'
910
+
911
+ expect ( fn1 ) . toBeCalledTimes ( 2 )
912
+ } )
913
+
914
+ test ( 'batch execute autorun cause by deep indirect dependency' , ( ) => {
915
+ const obs : any = observable ( { aa : 1 , bb : 1 , cc : 1 } )
916
+ const fn = jest . fn ( )
917
+ const fn2 = jest . fn ( )
918
+ const fn3 = jest . fn ( )
919
+
920
+ autorun ( ( ) => fn ( ( obs . aa = obs . bb + obs . cc ) ) )
921
+ autorun ( ( ) => fn2 ( ( obs . bb = obs . aa + obs . cc ) ) )
922
+ autorun ( ( ) => fn3 ( ( obs . cc = obs . aa + obs . bb ) ) )
923
+
924
+ // 嵌套写法重复调用没意义,只需要确保最新被触发的 reaction 执行,已过时的 reaction 可以忽略
925
+ // 比如 fn3 执行,触发 fn 和 fn2,fn 执行又触发 fn2,之前触发的 fn2 是过时的,忽略处理,fn2 只执行一次
926
+ expect ( fn ) . toBeCalledTimes ( 3 )
927
+ expect ( fn2 ) . toBeCalledTimes ( 2 )
928
+ expect ( fn3 ) . toBeCalledTimes ( 1 )
929
+
930
+ fn . mockClear ( )
931
+ fn2 . mockClear ( )
932
+ fn3 . mockClear ( )
933
+
934
+ batch ( ( ) => {
935
+ obs . aa = 100
936
+ obs . bb = 100
937
+ obs . cc = 100
938
+ } )
939
+
940
+ expect ( fn ) . toBeCalledTimes ( 1 )
941
+ expect ( fn2 ) . toBeCalledTimes ( 1 )
942
+ expect ( fn3 ) . toBeCalledTimes ( 1 )
943
+ } )
944
+
945
+ test ( 'multiple update should trigger only one' , ( ) => {
946
+ const obs = observable ( { aa : 1 , bb : 1 } )
947
+
948
+ autorun ( ( ) => {
949
+ obs . aa = obs . bb + 1
950
+ obs . bb = obs . aa + 1
951
+ } )
952
+
953
+ expect ( obs . aa ) . toBe ( 2 )
954
+ expect ( obs . bb ) . toBe ( 3 )
955
+
956
+ autorun ( ( ) => {
957
+ obs . aa = obs . bb + 1
958
+ obs . bb = obs . aa + 1
959
+ } )
960
+
961
+ expect ( obs . aa ) . toBe ( 6 )
962
+ expect ( obs . bb ) . toBe ( 7 )
963
+ } )
0 commit comments