Heim  >  Artikel  >  Web-Frontend  >  Vue3 berechnet und analysiert den Quellcode

Vue3 berechnet und analysiert den Quellcode

PHPz
PHPznach vorne
2023-05-11 19:49:10863Durchsuche

    computed

    Computed und Watch werden in Interviews oft nach ihren Unterschieden gefragt, also schauen wir uns ihre spezifische Implementierung anhand der Quellcode-Implementierung an

    // packages/reactivity/src/computed.ts
    export function computed<T>(
      getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>,
      debugOptions?: DebuggerOptions,
      isSSR = false
    ) {
      let getter: ComputedGetter<T>
      let setter: ComputedSetter<T>
      const onlyGetter = isFunction(getterOrOptions)
      if (onlyGetter) {
        getter = getterOrOptions
        setter = __DEV__
          ? () => {
              console.warn(&#39;Write operation failed: computed value is readonly&#39;)
            }
          : NOOP
      } else {
        getter = getterOrOptions.get
        setter = getterOrOptions.set
      }
      // new ComputedRefImpl
      const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR)
      if (__DEV__ && debugOptions && !isSSR) {
        cRef.effect.onTrack = debugOptions.onTrack
        cRef.effect.onTrigger = debugOptions.onTrigger
      }
      // 返回ComputedRefImpl实例
      return cRef as any
    }

    Sie können sehen, dass Computed intern zuerst nur Getter und Setter verarbeitet. und dann wird ein neues ComputedRefImpl zurückgegeben. Wenn Sie die Implementierung der Ref-API kennen, können Sie feststellen, dass ihre Implementierungen viele Ähnlichkeiten aufweisen von ref (für diejenigen, die mit der ref-Implementierung nicht vertraut sind, lesen Sie bitte das vorherige Kapitel), der einzige Unterschied besteht in der Beurteilung des _dirty-Werts. Dies ist, was wir oft sagen, dass der berechnete Wert den Wert zwischenspeichert Wert muss aktualisiert werden?

    Sie können sehen, dass im berechneten Konstruktor eine Beziehung zwischen einem Getter und seinen internen Antwortdaten hergestellt wird. Dies ist dieselbe wie die Beziehung zwischen unserer Komponentenaktualisierungsfunktion und den Antwortdaten, also den Antwortdaten, die sich auf den Getter beziehen Wenn die Zeit geändert wird, wird der dem Getter-Effekt entsprechende Scheduler ausgelöst. Hier wird _dirty auf true gesetzt und der gesammelte Effekt ausgeführt (dies ist normalerweise der Effekt der im Get gesammelten Funktion). Die Funktion „Aktualisieren“ wird ausgeführt, der berechnete Get wird erneut ausgelöst. Zu diesem Zeitpunkt wurde Dirty auf „True“ gesetzt, der Getter wird erneut ausgeführt, um den neuen Wert zurückzugeben, und der Wert wird in _vlaue zwischengespeichert.

    Zusammenfassung:

    So computed verfügt über zwei Ebenen der reaktionsfähigen Verarbeitung. Eine Ebene ist die Beziehung zwischen berechnetem Wert und der Wirkung der Funktion (ähnlich der Implementierung von ref), und die andere Ebene ist der berechnete Getter und die reaktionsfähigen Daten . Beziehung.

    Hinweis: Wenn Sie vorsichtig genug sind, werden Sie feststellen, dass zwischen der Auslösung des Effekts der Funktionsaktualisierungsfunktion und der Auslösung des berechneten Getter-Effekts möglicherweise ein Sequenzproblem besteht. Wenn ein reaktionsfähiges Datenelement a vorhanden ist, das nicht nur im Getter vorhanden ist, sondern auch früher als der Getter im Funktionsrendering aufgerufen wird, wird der Effekt der Aktualisierungsfunktion in der entsprechenden Dep früher erfasst als der Effekt des Wenn a geändert wird, wird zuerst der Effekt der Aktualisierungsfunktion ausgeführt. Wenn die Renderfunktion dann auf berechneten Wert zugreift, stellt sie fest, dass _dirty immer noch falsch ist, da der Effekt des Getters nicht ausgeführt wurde wird zu diesem Zeitpunkt immer noch der alte Wert sein. Die Lösung hierfür in vue3 besteht darin, dass beim Ausführen von Effekten zuerst die Effekte ausgeführt werden, die berechnet werden (auch im vorherigen Kapitel erwähnt):

    // packages/reactivity/src/computed.ts
    export class ComputedRefImpl<T> {
      public dep?: Dep = undefined // 存储effect的集合
      private _value!: T
      public readonly effect: ReactiveEffect<T>
      public readonly __v_isRef = true
      public readonly [ReactiveFlags.IS_READONLY]: boolean = false
      public _dirty = true // 是否需要重新更新value
      public _cacheable: boolean
      constructor(
        getter: ComputedGetter<T>,
        private readonly _setter: ComputedSetter<T>,
        isReadonly: boolean,
        isSSR: boolean
      ) {
        // 创建effect
        this.effect = new ReactiveEffect(getter, () => {
          // 调度器执行 重新赋值_dirty为true
          if (!this._dirty) {
            this._dirty = true
            // 触发effect
            triggerRefValue(this)
          }
        })
        // 用于区分effect是否是computed
        this.effect.computed = this
        this.effect.active = this._cacheable = !isSSR
        this[ReactiveFlags.IS_READONLY] = isReadonly
      }
      get value() {
        // the computed ref may get wrapped by other proxies e.g. readonly() #3376
        // computed ref可能被其他代理包装,例如readonly() #3376
        // 通过toRaw()获取原始值
        const self = toRaw(this)
        // 收集effect
        trackRefValue(self)
        // 如果是脏的,重新执行effect.run(),并且将_dirty设置为false
        if (self._dirty || !self._cacheable) {
          self._dirty = false
          // run()方法会执行getter方法 值会被缓存到self._value
          self._value = self.effect.run()!
        }
        return self._value
      }
      set value(newValue: T) {
        this._setter(newValue)
      }
    }

    watch

    watch ist einfacher als berechnet, da nur Getter und eingerichtet werden müssen Reaktionsfähigkeit Die Beziehung zwischen Daten besteht darin, den vom Benutzer übergebenen Rückruf aufzurufen, wenn sich die Reaktionsdaten ändern, und den alten und neuen Wert zu übergeben

    // packages/reactivity/src/effect.ts
    export function triggerEffects(
      dep: Dep | ReactiveEffect[],
      debuggerEventExtraInfo?: DebuggerEventExtraInfo
    ) {
      // spread into array for stabilization
      const effects = isArray(dep) ? dep : [...dep]
      // computed的effect会先执行
      // 防止render获取computed值得时候_dirty还没有置为true
      for (const effect of effects) {
        if (effect.computed) {
          triggerEffect(effect, debuggerEventExtraInfo)
        }
      }
      for (const effect of effects) {
        if (!effect.computed) {
          triggerEffect(effect, debuggerEventExtraInfo)
        }
      }
    }
    // packages/runtime-core/src/apiWatch.ts
    export function watch<T = any, Immediate extends Readonly<boolean> = false>(
      source: T | WatchSource<T>,
      cb: any,
      options?: WatchOptions<Immediate>
    ): WatchStopHandle {
      if (__DEV__ && !isFunction(cb)) {
        warn(...)
      }
      // watch 具体实现
      return doWatch(source as any, cb, options)
    }

    Das obige ist der detaillierte Inhalt vonVue3 berechnet und analysiert den Quellcode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen