• 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
16/**
17 *
18 * This file includes only framework internal classes and functions
19 * non are part of SDK. Do not access from app.
20 *
21 */
22
23/**
24 * ComputedV2
25 * one ComputedV2 object per @Computed variable
26 * computedId_ - similar to elmtId, identify one ComputedV2 in Observe.idToCmp Map
27 * observeObjectAccess = calculate the compute function and create dependencies to
28 * source variables
29 * fireChange - execute compute function and re-new dependencies with observeObjectAccess
30 */
31class ComputedV2 {
32
33  // start with high number to avoid same id as elmtId for components.
34  public static readonly MIN_COMPUTED_ID = 0x1000000000;
35  private static nextCompId_ = ComputedV2.MIN_COMPUTED_ID;
36
37  // name of @Computed property
38  private prop_: string;
39
40  // owning object of @Computed property
41  private target_: object;
42
43  // computation function for property
44  private propertyComputeFunc_: () => any;
45  private computedId_: number;
46
47  public static readonly COMPUTED_PREFIX = '___comp_';
48  public static readonly COMPUTED_CACHED_PREFIX = '___comp_cached_';
49
50  constructor(target: object, prop: string, func: (...args: any[]) => any) {
51    this.target_ = target;
52    this.propertyComputeFunc_ = func;
53    this.computedId_ = ++ComputedV2.nextCompId_;
54    this.prop_ = prop;
55  }
56
57  public InitRun(): number {
58    let cachedProp = ComputedV2.COMPUTED_CACHED_PREFIX + this.prop_;
59    let propertyKey = this.prop_;
60    Reflect.defineProperty(this.target_, propertyKey, {
61      get() {
62        ObserveV2.getObserve().addRef(this, propertyKey);
63        return ObserveV2.autoProxyObject(this, cachedProp);
64      },
65      enumerable: true
66    });
67
68    this.target_[cachedProp] = this.observeObjectAccess();
69    return this.computedId_;
70  }
71
72  public fireChange(): void {
73    let newVal = this.observeObjectAccess();
74    let cachedProp = ComputedV2.COMPUTED_CACHED_PREFIX + this.prop_;
75    if (this.target_[cachedProp] !== newVal) {
76      this.target_[cachedProp] = newVal;
77        ObserveV2.getObserve().fireChange(this.target_, this.prop_);
78    }
79  }
80
81  public getTarget() : object {
82    return this.target_;
83  }
84
85  public getProp() : string {
86    return this.prop_;
87  }
88
89  // register current watchId while executing compute function
90  private observeObjectAccess(): Object | undefined {
91    ObserveV2.getObserve().startRecordDependencies(this, this.computedId_);
92    let ret;
93
94    try {
95        ret = this.propertyComputeFunc_.call(this.target_);
96    } catch (e) {
97        stateMgmtConsole.applicationError(`@Computed Exception caught for ${this.propertyComputeFunc_.name}`, e.toString());
98        ret = undefined;
99        throw e;
100    } finally {
101        ObserveV2.getObserve().stopRecordDependencies();
102    }
103
104    return ret;
105  }
106}
107
108interface AsyncAddComputedJobEntryV2 {
109  target: Object;
110  name: string;
111}
112class AsyncAddComputedV2 {
113  static computedVars : Array<AsyncAddComputedJobEntryV2> = new Array<AsyncAddComputedJobEntryV2>();
114
115  static addComputed(target: Object, name: string): void {
116    if (AsyncAddComputedV2.computedVars.length === 0) {
117      Promise.resolve(true)
118      .then(AsyncAddComputedV2.run)
119      .catch(error => {
120        stateMgmtConsole.applicationError(`Exception caught in @Computed ${name}`, error);
121        _arkUIUncaughtPromiseError(error);
122      });
123    }
124    AsyncAddComputedV2.computedVars.push({target: target, name: name});
125  }
126
127  static run(): void {
128    AsyncAddComputedV2.computedVars.forEach((computedVar : AsyncAddComputedJobEntryV2) =>
129      ObserveV2.getObserve().constructComputed(computedVar.target, computedVar.name));
130    // according to stackoverflow this is the fastest way to clear an Array
131    // ref https://stackoverflow.com/questions/1232040/how-do-i-empty-an-array-in-javascript
132    AsyncAddComputedV2.computedVars.length = 0;
133  }
134}
135