@@ -70,4 +70,78 @@ describe('memoize decorator', () => {
7070 expect ( memoizationCheckCount ) . toBe ( 1 ) ; // 1memoized
7171 expect ( fib5 ) . toBe ( 8 ) ;
7272 } ) ;
73+
74+ it ( 'should memoize async function results and prevent redundant calls' , async ( ) => {
75+ let memoizationCheckCount = 0 ;
76+ let memoizedCalls = 0 ;
77+ let totalFunctionCalls = 0 ;
78+
79+ class DataService {
80+ @memoize ( async ( memoContext : MemoizationContext < string > ) => {
81+ memoizationCheckCount ++ ;
82+ if ( memoContext . isMemoized ) {
83+ memoizedCalls ++ ;
84+ }
85+ } )
86+ async fetchData ( id : number ) : Promise < string > {
87+ totalFunctionCalls ++ ;
88+ return new Promise ( ( resolve ) =>
89+ setTimeout ( ( ) => resolve ( `Data for ID: ${ id } ` ) , 100 )
90+ ) ;
91+ }
92+
93+ @memoize ( async ( memoContext : MemoizationContext < string > ) => {
94+ memoizationCheckCount ++ ;
95+ if ( memoContext . isMemoized ) {
96+ memoizedCalls ++ ;
97+ }
98+ } ) async throwData ( name : string ) : Promise < string > {
99+ totalFunctionCalls ++ ;
100+ throw new Error ( `hello ${ name } but I throw!` ) ;
101+ }
102+ }
103+
104+ const service = new DataService ( ) ;
105+
106+ memoizationCheckCount = 0 ;
107+ memoizedCalls = 0 ;
108+ totalFunctionCalls = 0 ;
109+
110+ const result1 = await service . fetchData ( 1 ) ;
111+ expect ( result1 ) . toBe ( 'Data for ID: 1' ) ;
112+ expect ( memoizedCalls ) . toBe ( 0 ) ;
113+ expect ( totalFunctionCalls ) . toBe ( 1 ) ;
114+ expect ( memoizationCheckCount ) . toBe ( 1 ) ; // Called once
115+
116+ const result2 = await service . fetchData ( 1 ) ;
117+ expect ( result2 ) . toBe ( 'Data for ID: 1' ) ;
118+ expect ( memoizedCalls ) . toBe ( 1 ) ; // Now it should be memoized
119+ expect ( totalFunctionCalls ) . toBe ( 1 ) ; // No new calls
120+ expect ( memoizationCheckCount ) . toBe ( 2 ) ; // Checked twice
121+
122+ const result3 = await service . fetchData ( 2 ) ;
123+ expect ( result3 ) . toBe ( 'Data for ID: 2' ) ;
124+ expect ( memoizedCalls ) . toBe ( 1 ) ; // No extra memoized calls yet
125+ expect ( totalFunctionCalls ) . toBe ( 2 ) ; // New call for different ID
126+ expect ( memoizationCheckCount ) . toBe ( 3 ) ; // Three checks (1st, 2nd for ID 1, and 3rd for ID 2)
127+
128+ const result4 = await service . fetchData ( 2 ) ;
129+ expect ( result4 ) . toBe ( 'Data for ID: 2' ) ;
130+ expect ( memoizedCalls ) . toBe ( 2 ) ; // ID 2 result is now memoized
131+ expect ( totalFunctionCalls ) . toBe ( 2 ) ; // No extra new calls
132+ expect ( memoizationCheckCount ) . toBe ( 4 ) ; // 4 checks in total
133+
134+ // test memoize a throwing async method
135+ memoizationCheckCount = 0 ;
136+ memoizedCalls = 0 ;
137+ totalFunctionCalls = 0 ;
138+ await Promise . all ( [
139+ expect ( service . throwData ( 'akram' ) ) . rejects . toThrow ( 'hello akram but I throw!' ) ,
140+ expect ( service . throwData ( 'akram' ) ) . rejects . toThrow ( 'hello akram but I throw!' ) ,
141+ expect ( service . throwData ( 'akram' ) ) . rejects . toThrow ( 'hello akram but I throw!' )
142+ ] ) ;
143+ expect ( memoizationCheckCount ) . toEqual ( totalFunctionCalls + memoizedCalls ) ;
144+ expect ( memoizedCalls ) . toEqual ( 2 ) ;
145+ expect ( totalFunctionCalls ) . toBe ( 1 ) ; // No extra new calls
146+ } ) ;
73147} ) ;
0 commit comments