Skip to content

Commit 69d7233

Browse files
committed
handle the reset correctly by implementing canceller
1 parent 78c52ab commit 69d7233

File tree

1 file changed

+67
-38
lines changed

1 file changed

+67
-38
lines changed

tensorboard/components/tf_dashboard_common/data-loader-behavior.ts

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)