亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Vue3源碼分析偵聽器watch的實現(xiàn)原理

 更新時間:2022年08月09日 16:19:52   作者:紫圣  
watch?的本質(zhì)就是觀測一個響應(yīng)式數(shù)據(jù),當(dāng)數(shù)據(jù)發(fā)生變化時通知并執(zhí)行相應(yīng)的回調(diào)函數(shù)。watch的實現(xiàn)利用了effect?和?options.scheduler?選項,這篇文章主要介紹了Vue3源碼分析偵聽器watch的實現(xiàn)原理,需要的朋友可以參考下

watch 的本質(zhì)

所謂的watch,其本質(zhì)就是觀測一個響應(yīng)式數(shù)據(jù),當(dāng)數(shù)據(jù)發(fā)生變化時通知并執(zhí)行相應(yīng)的回調(diào)函數(shù)。實際上,watch 的實現(xiàn)本質(zhì)就是利用了 effect 和 options.scheduler 選項。如下例子所示:

// watch 函數(shù)接收兩個參數(shù),source 是響應(yīng)式數(shù)據(jù),cb 是回調(diào)函數(shù)
function watch(source, cb){
  effect(
    // 觸發(fā)讀取操作,從而建立聯(lián)系
  	() => source.foo,
    {
      scheduler(){
        // 當(dāng)數(shù)據(jù)變化時,調(diào)用回調(diào)函數(shù) cb
        cb()
      }
    }
  )
}

如上面的代碼所示嗎,source 是響應(yīng)式數(shù)據(jù),cb 是回調(diào)函數(shù)。如果副作用函數(shù)中存在 scheduler 選項,當(dāng)響應(yīng)式數(shù)據(jù)發(fā)生變化時,會觸發(fā) scheduler 函數(shù)執(zhí)行,而不是直接觸發(fā)副作用函數(shù)執(zhí)行。從這個角度來看, scheduler 調(diào)度函數(shù)就相當(dāng)于是一個回調(diào)函數(shù),而 watch 的實現(xiàn)就是利用了這點。

watch 的函數(shù)簽名

偵聽多個源

偵聽的數(shù)據(jù)源可以 是一個數(shù)組,如下面的函數(shù)簽名所示:

// packages/runtime-core/src/apiWatch.ts

// 數(shù)據(jù)源是一個數(shù)組
// overload: array of multiple sources + cb
export function watch<
  T extends MultiWatchSources,
  Immediate extends Readonly<boolean> = false
>(
  sources: [...T],
  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
  options?: WatchOptions<Immediate>
): WatchStopHandle

也可以使用數(shù)組同時偵聽多個源,如下面的函數(shù)簽名所示:

// packages/runtime-core/src/apiWatch.ts

// 使用數(shù)組同時偵聽多個源
// overload: multiple sources w/ `as const`
// watch([foo, bar] as const, () => {})
// somehow [...T] breaks when the type is readonly
export function watch<
  T extends Readonly<MultiWatchSources>,
  Immediate extends Readonly<boolean> = false
>(
  source: T,
  cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
  options?: WatchOptions<Immediate>
): WatchStopHandle

偵聽單一源

偵聽的數(shù)據(jù)源是一個 ref 類型的數(shù)據(jù) 或者是一個具有返回值的 getter 函數(shù),如下面的函數(shù)簽名所示:

// packages/runtime-core/src/apiWatch.ts

// 數(shù)據(jù)源是一個 ref 類型的數(shù)據(jù) 或者是一個具有返回值的 getter 函數(shù)
// overload: single source + cb
export function watch<T, Immediate extends Readonly<boolean> = false>(
source: WatchSource<T>,
 cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
 options?: WatchOptions<Immediate>
): WatchStopHandle

export type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)

偵聽的數(shù)據(jù)源是一個響應(yīng)式的 obj 對象,如下面的函數(shù)簽名所示:

// packages/runtime-core/src/apiWatch.ts

// 數(shù)據(jù)源是一個響應(yīng)式的 obj 對象
// overload: watching reactive object w/ cb
export function watch<
  T extends object,
  Immediate extends Readonly<boolean> = false
>(
  source: T,
  cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
  options?: WatchOptions<Immediate>
): WatchStopHandle

watch 的實現(xiàn)

watch 函數(shù)

// packages/runtime-core/src/apiWatch.ts

// implementation
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(fn, options?)\` signature has been moved to a separate API. ` +
        `Use \`watchEffect(fn, options?)\` instead. \`watch\` now only ` +
        `supports \`watch(source, cb, options?) signature.`
    )
  }
  return doWatch(source as any, cb, options)
}

可以看到,watch 函數(shù)接收3個參數(shù),分別是:source 偵聽的數(shù)據(jù)源,cb 回調(diào)函數(shù),options 偵聽選項。

source 參數(shù)

從watch的函數(shù)重載中可以知道,當(dāng)偵聽的是單一源時,source 可以是一個 ref 類型的數(shù)據(jù) 或者是一個具有返回值的 getter 函數(shù),也可以是一個響應(yīng)式的 obj 對象。當(dāng)偵聽的是多個源時,source 可以是一個數(shù)組。

cb 參數(shù)

在 cb 回調(diào)函數(shù)中,給開發(fā)者提供了最新的value,舊的value以及onCleanup函數(shù)用與清除副作用。如下面的類型定義所示:

export type WatchCallback<V = any, OV = any> = (
  value: V,
  oldValue: OV,
  onCleanup: OnCleanup
) => any

options 參數(shù)

options 選項可以控制 watch 的行為,例如通過options的選項參數(shù)immediate來控制watch的回調(diào)是否立即執(zhí)行,通過options的選項參數(shù)來控制watch的回調(diào)函數(shù)是同步執(zhí)行還是異步執(zhí)行。options 參數(shù)的類型定義如下:

export interface WatchOptionsBase extends DebuggerOptions {
  flush?: 'pre' | 'post' | 'sync'
}
export interface WatchOptions<Immediate = boolean> extends WatchOptionsBase {
  immediate?: Immediate
  deep?: boolean
}

可以看到 options 的類型定義 WatchOptions 繼承了 WatchOptionsBase。也就是說,watch 的 options 中除了 immediate 和 deep 這兩個特有的參數(shù)外,還可以傳遞 WatchOptionsBase 中的所有參數(shù)以控制副作用執(zhí)行的行為。

在 watch 的函數(shù)體中調(diào)用了 doWatch 函數(shù),我們來看看它的實現(xiàn)。

doWatch 函數(shù)

實際上,無論是watch函數(shù),還是 watchEffect 函數(shù),在執(zhí)行時最終調(diào)用的都是 doWatch 函數(shù)。

doWatch 函數(shù)簽名

function doWatch(
  source: WatchSource | WatchSource[] | WatchEffect | object,
  cb: WatchCallback | null,
  { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle

doWatch 的函數(shù)簽名與 watch 的函數(shù)簽名基本一致,也是接收三個參數(shù)。在 doWatch 函數(shù)中,為了便于options 選項的使用,對 options 進行了解構(gòu)。

初始化變量

首先從 component 中獲取當(dāng)前的組件實例,然后分別定義三個變量。其中 getter 是一個函數(shù),她或作為副作用的函數(shù)參數(shù)傳入到副作用函數(shù)中。forceTrigger 變量是一個布爾值,用來標(biāo)識是否需要強制觸發(fā)副作用函數(shù)執(zhí)行。isMultiSource 變量同樣也是一個布爾值,用來標(biāo)記偵聽的數(shù)據(jù)源是單一源還是以數(shù)組形式傳入的多個源,初始值為 false,表示偵聽的是單一源。如下面的代碼所示:

  const instance = currentInstance
  let getter: () => any
  // 是否需要強制觸發(fā)副作用函數(shù)執(zhí)行   
  let forceTrigger = false
  // 偵聽的是否是多個源
  let isMultiSource = false

接下來根據(jù)偵聽的數(shù)據(jù)源來初始化這三個變量。

偵聽的數(shù)據(jù)源是一個 ref 類型的數(shù)據(jù)

當(dāng)偵聽的數(shù)據(jù)源是一個 ref 類型的數(shù)據(jù)時,通過返回 source.value 來初始化 getter,也就是說,當(dāng) getter 函數(shù)被觸發(fā)時,會通過source.value 獲取到實際偵聽的數(shù)據(jù)。然后通過 isShallow 函數(shù)來判斷偵聽的數(shù)據(jù)源是否是淺響應(yīng),并將其結(jié)果賦值給 forceTrigger,完成 forceTrigger 變量的初始化。如下面的代碼所示:

if (isRef(source)) {
  // 偵聽的數(shù)據(jù)源是 ref
  getter = () => source.value
  // 判斷數(shù)據(jù)源是否是淺響應(yīng)
  forceTrigger = isShallow(source)
}

偵聽的數(shù)據(jù)源是一個響應(yīng)式數(shù)據(jù)

當(dāng)偵聽的數(shù)據(jù)源是一個響應(yīng)式數(shù)據(jù)時,直接返回 source 來初始化 getter ,即 getter 函數(shù)被觸發(fā)時直接返回 偵聽的數(shù)據(jù)源。由于響應(yīng)式數(shù)據(jù)中可能會是一個object 對象,因此將 deep 設(shè)置為 true,在觸發(fā) getter 函數(shù)時可以遞歸地讀取對象的屬性值。如下面的代碼所示:

else if (isReactive(source)) {
  // 偵聽的數(shù)據(jù)源是響應(yīng)式數(shù)據(jù)
  getter = () => source
  deep = true
}

偵聽的數(shù)據(jù)源是一個數(shù)組

當(dāng)偵聽的數(shù)據(jù)源是一個數(shù)組,即同時偵聽多個源。此時直接將 isMultiSource 變量設(shè)置為 true,表示偵聽的是多個源。接著通過數(shù)組的 some 方法來檢測偵聽的多個源中是否存在響應(yīng)式對象,將其結(jié)果賦值給 forceTrigger 。然后遍歷數(shù)組,判斷每個源的類型,從而完成 getter 函數(shù)的初始化。如下面的代碼所示:

else if (isArray(source)) {
  // 偵聽的數(shù)據(jù)源是一個數(shù)組,即同時偵聽多個源
  isMultiSource = true
  forceTrigger = source.some(isReactive)
  getter = () =>
    // 遍歷數(shù)組,判斷每個源的類型 
    source.map(s => {
      if (isRef(s)) {
        // 偵聽的數(shù)據(jù)源是 ref  
        return s.value
      } else if (isReactive(s)) {
        // 偵聽的數(shù)據(jù)源是響應(yīng)式數(shù)據(jù) 
        return traverse(s)
      } else if (isFunction(s)) {
        // 偵聽的數(shù)據(jù)源是一個具有返回值的 getter 函數(shù) 
        return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
      } else {
        __DEV__ && warnInvalidSource(s)
      }
    })
} 

偵聽的數(shù)據(jù)源是一個函數(shù)

當(dāng)偵聽的數(shù)據(jù)源是一個具有返回值的 getter 函數(shù)時,判斷 doWatch 函數(shù)的第二個參數(shù) cb 是否有傳入。如果有傳入,則處理的是 watch 函數(shù)的場景,此時執(zhí)行 source 函數(shù),將執(zhí)行結(jié)果賦值給 getter 。如果沒有傳入,則處理的是 watchEffect 函數(shù)的場景。在該場景下,如果組件實例已經(jīng)卸載,則直接返回,不執(zhí)行 source 函數(shù)。否則就執(zhí)行 cleanup 清除依賴,然后執(zhí)行 source 函數(shù),將執(zhí)行結(jié)果賦值給 getter 。如下面的代碼所示:

else if (isFunction(source)) {

  // 處理 watch 和 watchEffect 的場景
  // watch 的第二個參數(shù)可以是一個具有返回值的 getter 參數(shù),第二個參數(shù)是一個回調(diào)函數(shù)
  // watchEffect 的參數(shù)是一個 函數(shù)

  // 偵聽的數(shù)據(jù)源是一個具有返回值的 getter 函數(shù) 
  if (cb) {
    // getter with cb
    // 處理的是 watch 的場景
    // 執(zhí)行 source 函數(shù),將執(zhí)行結(jié)果賦值給 getter   
    getter = () =>
      callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
  } else {
    // no cb -> simple effect
    // 沒有回調(diào),即為 watchEffect 的場景  
    getter = () => {
      // 件實例已經(jīng)卸載,則不執(zhí)行,直接返回
      if (instance && instance.isUnmounted) {
        return
      }
      // 清除依賴
      if (cleanup) {
        cleanup()
      }
      // 執(zhí)行 source 函數(shù)
      return callWithAsyncErrorHandling(
        source,
        instance,
        ErrorCodes.WATCH_CALLBACK,
        [onCleanup]
      )
    }
  }
}

遞歸讀取響應(yīng)式數(shù)據(jù)

如果偵聽的數(shù)據(jù)源是一個響應(yīng)式數(shù)據(jù),需要遞歸讀取響應(yīng)式數(shù)據(jù)中的屬性值。如下面的代碼所示:

// 處理的是 watch 的場景
// 遞歸讀取對象的屬性值  
if (cb && deep) {
  const baseGetter = getter
  getter = () => traverse(baseGetter())
}

在上面的代碼中,doWatch 函數(shù)的第二個參數(shù) cb 有傳入,說明處理的是 watch 中的場景。deep 變量為 true ,說明此時偵聽的數(shù)據(jù)源是一個響應(yīng)式數(shù)據(jù),因此需要調(diào)用 traverse 函數(shù)來遞歸讀取數(shù)據(jù)源中的每個屬性,對其進行監(jiān)聽,從而當(dāng)任意屬性發(fā)生變化時都能夠觸發(fā)回調(diào)函數(shù)執(zhí)行。

定義清除副作用函數(shù)

聲明 cleanup 和 onCleanup 函數(shù),并在 onCleanup 函數(shù)的執(zhí)行過程中給 cleanup 函數(shù)賦值,當(dāng)副作用函數(shù)執(zhí)行一些異步的副作用時,這些響應(yīng)需要在其失效是清除。如下面的代碼所示:

// 清除副作用函數(shù)
let cleanup: () => void
let onCleanup: OnCleanup = (fn: () => void) => {
  cleanup = effect.onStop = () => {
    callWithErrorHandling(fn, instance, ErrorCodes.WATCH_CLEANUP)
  }
}

封裝 scheduler 調(diào)度函數(shù)

為了便于控制 watch 的回調(diào)函數(shù) cb 的執(zhí)行時機,需要將 scheduler 調(diào)度函數(shù)封裝為一個獨立的 job 函數(shù),如下面的代碼所示:

// 將 scheduler 調(diào)度函數(shù)封裝為一個獨立的 job 函數(shù),便于在初始化和變更時執(zhí)行它
const job: SchedulerJob = () => {
  if (!effect.active) {
    return
  }
  if (cb) {
    // 處理 watch 的場景 
    // watch(source, cb)

    // 執(zhí)行副作用函數(shù)獲取新值
    const newValue = effect.run()
    
    // 如果數(shù)據(jù)源是響應(yīng)式數(shù)據(jù)或者需要強制觸發(fā)副作用函數(shù)執(zhí)行或者新舊值發(fā)生了變化
    // 則執(zhí)行回調(diào)函數(shù),并更新舊值
    if (
      deep ||
      forceTrigger ||
      (isMultiSource
        ? (newValue as any[]).some((v, i) =>
            hasChanged(v, (oldValue as any[])[i])
          )
        : hasChanged(newValue, oldValue)) ||
      (__COMPAT__ &&
        isArray(newValue) &&
        isCompatEnabled(DeprecationTypes.WATCH_ARRAY, instance))
    ) {
      
      // 當(dāng)回調(diào)再次執(zhí)行前先清除副作用
      // cleanup before running cb again
      if (cleanup) {
        cleanup()
      }

      // 執(zhí)行watch 函數(shù)的回調(diào)函數(shù) cb,將舊值和新值作為回調(diào)函數(shù)的參數(shù)
      callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
        newValue,
        
        // 首次調(diào)用時,將 oldValue 的值設(shè)置為 undefined
        // pass undefined as the old value when it's changed for the first time
        oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue,
        onCleanup
      ])
      // 更新舊值,不然下一次會得到錯誤的舊值
      oldValue = newValue
    }
  } else {
    // watchEffect
    // 處理 watchEffect 的場景
    effect.run()
  }
}

在 job 函數(shù)中,判斷回調(diào)函數(shù) cb 是否傳入,如果有傳入,那么是 watch 函數(shù)被調(diào)用的場景,否則就是 watchEffect 函數(shù)被調(diào)用的場景。

如果是 watch 函數(shù)被調(diào)用的場景,首先執(zhí)行副作用函數(shù),將執(zhí)行結(jié)果賦值給 newValue 變量,作為最新的值。然后判斷需要執(zhí)行回調(diào)函數(shù) cb 的情況:

  • 如果偵聽的數(shù)據(jù)源是響應(yīng)式數(shù)據(jù),需要深度偵聽,即 deep 為 true
  • 如果需要強制觸發(fā)副作用函數(shù)執(zhí)行,即 forceTrigger 為 true
  • 如果新舊值發(fā)生了變化

只要滿足上面三種情況中的其中一種,就需要執(zhí)行 watch 函數(shù)的回調(diào)函數(shù) cb。如果回調(diào)函數(shù) cb 是再次執(zhí)行,在執(zhí)行之前需要先清除副作用。然后調(diào)用 callWithAsyncErrorHandling 函數(shù)執(zhí)行回調(diào)函數(shù)cb,并將新值newValue 和舊值 oldValue 傳入回調(diào)函數(shù)cb中。在回調(diào)函數(shù)cb執(zhí)行后,更新舊值oldValue,避免在下一次執(zhí)行回調(diào)函數(shù)cb時獲取到錯誤的舊值。

如果是 watchEffect 函數(shù)被調(diào)用的場景,則直接執(zhí)行副作用函數(shù)即可。

設(shè)置 job 的 allowRecurse 屬性

根據(jù)是否傳入回調(diào)函數(shù)cb,設(shè)置 job 函數(shù)的 allowRecurse 屬性。這個設(shè)置十分重要,它能夠讓 job 作為偵聽器的回調(diào),這樣調(diào)度器就能知道它允許調(diào)用自身。

// important: mark the job as a watcher callback so that scheduler knows
// it is allowed to self-trigger (#1727)
// 重要:讓調(diào)度器任務(wù)作為偵聽器的回調(diào)以至于調(diào)度器能知道它可以被允許自己派發(fā)更新
job.allowRecurse = !!cb

flush 選項指定回調(diào)函數(shù)的執(zhí)行時機

在調(diào)用 watch 函數(shù)時,可以通過 options 的 flush 選項來指定回調(diào)函數(shù)的執(zhí)行時機:

  • 當(dāng) flush 的值為 sync 時,代表調(diào)度器函數(shù)是同步執(zhí)行,此時直接將 job 賦值給 scheduler,這樣調(diào)度器函數(shù)就會直接執(zhí)行。

  • 當(dāng) flush 的值為 post 時,代表調(diào)度函數(shù)需要將副作用函數(shù)放到一個微任務(wù)隊列中,并等待 DOM 更新結(jié)束后再執(zhí)行。

  • 當(dāng) flush 的值為 pre 時,即調(diào)度器函數(shù)默認(rèn)的執(zhí)行方式,這時調(diào)度器會區(qū)分組件是否已經(jīng)掛載。如果組件未掛載,則先執(zhí)行一次調(diào)度函數(shù),即執(zhí)行回調(diào)函數(shù)cb。在組件掛載之后,將調(diào)度函數(shù)推入一個優(yōu)先執(zhí)行時機的隊列中。

    // 這里處理的是回調(diào)函數(shù)的執(zhí)行時機
    let scheduler: EffectScheduler if (flush === 'sync') { // 同步執(zhí)行,將 job 直接賦值給調(diào)度器 scheduler = job as any // the scheduler function gets called directly } else if (flush === 'post') { // 將調(diào)度函數(shù) job 添加到微任務(wù)隊列中執(zhí)行 scheduler = () => queuePostRenderEffect(job, instance && instance.suspense) } else { // default: 'pre' // 調(diào)度器函數(shù)默認(rèn)的執(zhí)行模式 scheduler = () => { if (!instance || instance.isMounted) { // 組件掛載后將 job 推入一個優(yōu)先執(zhí)行時機的隊列中 queuePreFlushCb(job) } else { // with 'pre' option, the first call must happen before // the component is mounted so it is called synchronously. // 在 pre 選型中,第一次調(diào)用必須發(fā)生在組件掛載之前 // 所以這次調(diào)用是同步的 job() } } }

創(chuàng)建副作用函數(shù)

初始化完 getter 函數(shù)和調(diào)度器函數(shù) scheduler 后,調(diào)用 ReactiveEffect 類來創(chuàng)建一個副作用函數(shù)

// 創(chuàng)建一個副作用函數(shù)
const effect = new ReactiveEffect(getter, scheduler)

執(zhí)行副作用函數(shù)

在執(zhí)行副作用函數(shù)之前,首先判斷是否傳入了回調(diào)函數(shù)cb,如果有傳入,則根據(jù) options 的 immediate 選項來判斷是否需要立即執(zhí)行回調(diào)函數(shù)cb,如果指定了immediate 選項,則立即執(zhí)行 job 函數(shù),即 watch 的回調(diào)函數(shù)會在 watch 創(chuàng)建時立即執(zhí)行一次。否則就手動調(diào)用副作用函數(shù),并將返回值作為舊值,賦值給 oldValue。如下面的代碼所示:

if (cb) {
  // 選項參數(shù) immediate 來指定回調(diào)是否需要立即執(zhí)行
  if (immediate) {
    // 回調(diào)函數(shù)會在 watch 創(chuàng)建時立即執(zhí)行一次
    job()
  } else {
    // 手動調(diào)用副作用函數(shù),拿到的就是舊值
    oldValue = effect.run()
  }
}

如果 options 的 flush 選項的值為 post ,需要將副作用函數(shù)放入到微任務(wù)隊列中,等待組件掛載完成后再執(zhí)行副作用函數(shù)。如下面的代碼所示:

else if (flush === 'post') {
  // 在調(diào)度器函數(shù)中判斷 flush 是否為 'post',如果是,將其放到微任務(wù)隊列中執(zhí)行
  queuePostRenderEffect(
    effect.run.bind(effect),
    instance && instance.suspense
  )
}

其余情況都是立即執(zhí)行副作用函數(shù)。如下面的代碼所示:

else {
  // 其余情況立即首次執(zhí)行副作用
  effect.run()
}

返回匿名函數(shù),停止偵聽

doWatch 函數(shù)最后返回了一個匿名函數(shù),該函數(shù)用以結(jié)束數(shù)據(jù)源的偵聽。因此在調(diào)用 watch 或者 watchEffect 時,可以調(diào)用其返回值類結(jié)束偵聽。

return () => {
  effect.stop()
  if (instance && instance.scope) {
    // 返回一個函數(shù),用以顯式的結(jié)束偵聽
    remove(instance.scope.effects!, effect)
  }
}

總結(jié)

watch 的本質(zhì)就是觀測一個響應(yīng)式數(shù)據(jù),當(dāng)數(shù)據(jù)發(fā)生變化時通知并執(zhí)行相應(yīng)的回調(diào)函數(shù)。watch的實現(xiàn)利用了effect 和 options.scheduler 選項。

watch 可以偵聽單一源,也可以偵聽多個源。偵聽單一源時數(shù)據(jù)源可以是一個具有返回值的getter 函數(shù),或者是一個 ref 對象,也可以是一個響應(yīng)式的 object 對象。偵聽多個源時,其數(shù)據(jù)源是一個數(shù)組。

在watch的實現(xiàn)中,根據(jù)偵聽的數(shù)據(jù)源的類型來初始化getter 函數(shù)和 scheduler 調(diào)度函數(shù),根據(jù)這兩個函數(shù)創(chuàng)建一個副作用函數(shù),并根據(jù) options 的 immediate 選項以及 flush 選項來指定回調(diào)函數(shù)和副作用函數(shù)的執(zhí)行時機。當(dāng) immediate 為 true 時,在watch 創(chuàng)建時會立即執(zhí)行一次回調(diào)函數(shù)。當(dāng) flush 的值為 post 時,scheduler 調(diào)度函數(shù)和副作用函數(shù)都會被添加到微任務(wù)隊列中,會等待 DOM 更新結(jié)束后再執(zhí)行。

到此這篇關(guān)于Vue3源碼分析偵聽器watch的實現(xiàn)原理的文章就介紹到這了,更多相關(guān)Vue3偵聽器watch內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中如何使用vue-touch插件

    vue中如何使用vue-touch插件

    這篇文章主要介紹了vue中使用vue-touch插件的方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • 關(guān)于Vue新搭檔TypeScript快速入門實踐

    關(guān)于Vue新搭檔TypeScript快速入門實踐

    這篇文章主要介紹了關(guān)于Vue新搭檔TypeScript快速入門實踐,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • Vant picker選擇器設(shè)置默認(rèn)值導(dǎo)致選擇器失效的解決

    Vant picker選擇器設(shè)置默認(rèn)值導(dǎo)致選擇器失效的解決

    這篇文章主要介紹了Vant picker選擇器設(shè)置默認(rèn)值導(dǎo)致選擇器失效的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Vue3?props的使用示例詳解

    Vue3?props的使用示例詳解

    這篇文章主要介紹了Vue3?props的使用詳解,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-10-10
  • Vue?element-ui中表格過長內(nèi)容隱藏顯示的實現(xiàn)方式

    Vue?element-ui中表格過長內(nèi)容隱藏顯示的實現(xiàn)方式

    在Vue項目中,使用ElementUI渲染表格數(shù)據(jù)時,如果某一個列數(shù)值長度超過列寬,會默認(rèn)換行,造成顯示不友好,下面這篇文章主要給大家介紹了關(guān)于Vue?element-ui中表格過長內(nèi)容隱藏顯示的實現(xiàn)方式,需要的朋友可以參考下
    2022-09-09
  • Vue基礎(chǔ)語法知識梳理下篇

    Vue基礎(chǔ)語法知識梳理下篇

    這篇文章主要介紹了Vue基礎(chǔ)語法知識梳理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-12-12
  • vue中@click綁定事件點擊不生效的原因及解決方案

    vue中@click綁定事件點擊不生效的原因及解決方案

    根據(jù)Vue2.0官方文檔關(guān)于父子組件通訊的原則,父組件通過prop傳遞數(shù)據(jù)給子組件,子組件觸發(fā)事件給父組件,這篇文章主要介紹了vue中@click綁定事件點擊不生效的解決方案,需要的朋友可以參考下
    2022-12-12
  • vue router動態(tài)路由設(shè)置參數(shù)可選問題

    vue router動態(tài)路由設(shè)置參數(shù)可選問題

    這篇文章主要介紹了vue-router動態(tài)路由設(shè)置參數(shù)可選,文中給大家提到了vue-router 動態(tài)添加 路由的方法,需要的朋友可以參考下
    2019-08-08
  • 利用vue3+ts實現(xiàn)管理后臺(增刪改查)

    利用vue3+ts實現(xiàn)管理后臺(增刪改查)

    這篇文章主要介紹了利用vue3+ts實現(xiàn)管理后臺(增刪改查),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • VUE3中h()函數(shù)和createVNode()函數(shù)的使用解讀

    VUE3中h()函數(shù)和createVNode()函數(shù)的使用解讀

    這篇文章主要介紹了VUE3中h()函數(shù)和createVNode()函數(shù)的使用解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評論