@@ -106,6 +106,11 @@ namespace tf_dashboard_common {
106106 type : Object ,
107107 value : ( ) => new Map < CacheKey , LoadState > ( ) ,
108108 } ,
109+
110+ _canceller : {
111+ type : Object ,
112+ value : ( ) => new tf_backend . Canceller ( ) ,
113+ } ,
109114 } ,
110115
111116 observers : [ '_dataToLoadChanged(isAttached, dataToLoad.*)' ] ,
@@ -122,6 +127,8 @@ namespace tf_dashboard_common {
122127 reset ( ) {
123128 // https://github.com/tensorflow/tensorboard/issues/1499
124129 // Cannot use the observer to observe `loadKey` changes directly.
130+ this . cancelAsync ( this . _loadDataAsync ) ;
131+ if ( this . _canceller ) this . _canceller . cancelAll ( ) ;
125132 if ( this . _dataLoadState ) this . _dataLoadState . clear ( ) ;
126133 if ( this . isAttached ) this . _loadData ( ) ;
127134 } ,
@@ -138,6 +145,13 @@ namespace tf_dashboard_common {
138145 } ,
139146
140147 detached ( ) {
148+ // Note: Cannot call canceller.cancelAll since it will poison the cache.
149+ // detached gets called when a component gets unmounted from the document
150+ // but it can be re-mounted. When remounted, poisoned cache will manifest.
151+ // t=0: dataLoadState: 'a' = loading
152+ // t=10: unmount
153+ // t=20: request for 'a' resolves but we do not change the loadState
154+ // because we do not want to set one if, instead, it was resetted at t=10.
141155 this . cancelAsync ( this . _loadDataAsync ) ;
142156 } ,
143157
@@ -149,48 +163,63 @@ namespace tf_dashboard_common {
149163
150164 _loadDataImpl ( ) {
151165 if ( ! this . active ) return ;
152-
153166 this . cancelAsync ( this . _loadDataAsync ) ;
154- this . _loadDataAsync = this . async ( ( ) => {
155- // Read-only property have a special setter.
156- this . _setDataLoading ( true ) ;
157-
158- // Promises return cacheKeys of the data that were fetched.
159- const promises = this . dataToLoad
160- . filter ( ( datum ) => {
161- const cacheKey = this . getDataLoadName ( datum ) ;
162- return ! this . _dataLoadState . has ( cacheKey ) ;
163- } )
164- . map ( ( datum ) => {
165- const cacheKey = this . getDataLoadName ( datum ) ;
166- this . _dataLoadState . set ( cacheKey , LoadState . LOADING ) ;
167- return this . requestData ( datum ) . then ( ( value ) => {
168- this . _dataLoadState . set ( cacheKey , LoadState . LOADED ) ;
169- this . loadDataCallback ( this , datum , value ) ;
170- return cacheKey ;
167+ this . _loadDataAsync = this . async (
168+ this . _canceller . cancellable ( ( result ) => {
169+ if ( result . cancelled ) {
170+ return ;
171+ }
172+ // Read-only property have a special setter.
173+ this . _setDataLoading ( true ) ;
174+
175+ // Promises return cacheKeys of the data that were fetched.
176+ const promises = this . dataToLoad
177+ . filter ( ( datum ) => {
178+ const cacheKey = this . getDataLoadName ( datum ) ;
179+ return ! this . _dataLoadState . has ( cacheKey ) ;
180+ } )
181+ . map ( ( datum ) => {
182+ const cacheKey = this . getDataLoadName ( datum ) ;
183+ this . _dataLoadState . set ( cacheKey , LoadState . LOADING ) ;
184+ return this . requestData ( datum ) . then (
185+ this . _canceller . cancellable ( ( result ) => {
186+ // It was resetted. Do not notify of the response.
187+ if ( ! result . cancelled ) {
188+ this . _dataLoadState . set ( cacheKey , LoadState . LOADED ) ;
189+ this . loadDataCallback ( this , datum , result . value ) ;
190+ }
191+ return cacheKey ;
192+ } )
193+ ) ;
171194 } ) ;
172- } ) ;
173195
174- return Promise . all ( promises ) . then ( ( keysFetched ) => {
175- const fetched = new Set ( keysFetched ) ;
176- const shouldNotify = this . dataToLoad . some ( ( datum ) =>
177- fetched . has ( this . getDataLoadName ( datum ) )
196+ return Promise . all ( promises ) . then (
197+ this . _canceller . cancellable ( ( result ) => {
198+ // It was resetted. Do not notify of the data load.
199+ if ( ! result . cancelled ) {
200+ const keysFetched = result . value ;
201+ const fetched = new Set ( keysFetched ) ;
202+ const shouldNotify = this . dataToLoad . some ( ( datum ) =>
203+ fetched . has ( this . getDataLoadName ( datum ) )
204+ ) ;
205+
206+ if ( shouldNotify ) {
207+ this . onLoadFinish ( ) ;
208+ }
209+ }
210+
211+ const isDataFetchPending = Array . from (
212+ this . _dataLoadState . values ( )
213+ ) . some ( ( loadState ) => loadState === LoadState . LOADING ) ;
214+
215+ if ( ! isDataFetchPending ) {
216+ // Read-only property have a special setter.
217+ this . _setDataLoading ( false ) ;
218+ }
219+ } )
178220 ) ;
179-
180- if ( shouldNotify ) {
181- this . onLoadFinish ( ) ;
182- }
183-
184- const isDataFetchPending = Array . from (
185- this . _dataLoadState . values ( )
186- ) . some ( ( loadState ) => loadState === LoadState . LOADING ) ;
187-
188- if ( ! isDataFetchPending ) {
189- // Read-only property have a special setter.
190- this . _setDataLoading ( false ) ;
191- }
192- } ) ;
193- } ) ;
221+ } )
222+ ) ;
194223 } ,
195224 } ;
196225} // namespace tf_dashboard_common
0 commit comments