• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16interface ITimeProvider {
17  getCurrent: () => number;
18}
19
20class DefaultTimeProvider implements ITimeProvider {
21  getCurrent(): number {
22    return Date.now();
23  }
24}
25
26class Prefetcher implements IPrefetcher {
27  private datasource: IDataSourcePrefetching | null = null;
28  private readonly prefetchRangeEvaluator: IPrefetchRangeEvaluator;
29  private readonly timeProvider: ITimeProvider;
30
31  constructor(prefetchRangeEvaluator: IPrefetchRangeEvaluator, timeProvider: ITimeProvider) {
32    this.prefetchRangeEvaluator = prefetchRangeEvaluator;
33    this.timeProvider = timeProvider;
34  }
35
36  setDataSource(ds: IDataSourcePrefetching): void {
37    this.datasource = ds;
38    this.prefetchRangeEvaluator.setTotal(ds.totalCount());
39  }
40
41  visibleAreaChanged(minVisible: number, maxVisible: number): void {
42    if (!this.datasource) {
43      throw new Error('No data source');
44    }
45
46    const oldRangeToPrefetch = this.prefetchRangeEvaluator.rangeToPrefetch;
47    this.prefetchRangeEvaluator.visibleRangeChanged(minVisible, maxVisible);
48
49    this.prefetchDifference(oldRangeToPrefetch);
50    this.cancelDifference(oldRangeToPrefetch);
51  }
52
53  private prefetchDifference(oldRange: IndexRange): void {
54    this.prefetchRangeEvaluator.rangeToPrefetch.subtract(oldRange).forEachIndex((index) => {
55      const prefetchStart = this.timeProvider.getCurrent();
56
57      const prefetchedCallback = (): void => {
58        if (!this.prefetchRangeEvaluator.rangeToPrefetch.contains(index)) {
59          return;
60        }
61
62        const oldRangeToPrefetch = this.prefetchRangeEvaluator.rangeToPrefetch;
63
64        const prefetchDuration = this.timeProvider.getCurrent() - prefetchStart;
65        this.prefetchRangeEvaluator.itemPrefetched(index, prefetchDuration);
66
67        this.prefetchDifference(oldRangeToPrefetch);
68      };
69
70      const prefetchResponse = this.datasource!.prefetch(index);
71      if (prefetchResponse instanceof Promise) {
72        prefetchResponse.then(prefetchedCallback);
73      } else {
74        prefetchedCallback();
75      }
76    });
77  }
78
79  private cancelDifference(oldRangeToPrefetch: IndexRange): void {
80    if (!this.datasource!.cancel || this.prefetchRangeEvaluator.rangeToPrefetch.length > oldRangeToPrefetch.length) {
81      return;
82    }
83    oldRangeToPrefetch.subtract(this.prefetchRangeEvaluator.rangeToPrefetch).forEachIndex((index) => {
84      this.datasource!.cancel!(index);
85    });
86  }
87}
88