欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue中created、watch和computed的執(zhí)行順序詳解

 更新時(shí)間:2022年11月26日 09:38:21   作者:qb  
由于vue的雙向數(shù)據(jù)綁定,自動(dòng)更新數(shù)據(jù)的機(jī)制,在數(shù)據(jù)變化后,對(duì)此數(shù)據(jù)依賴?的所有數(shù)據(jù),watch事件都會(huì)被更新、觸發(fā),下面這篇文章主要給大家介紹了關(guān)于vue中created、watch和computed的執(zhí)行順序,需要的朋友可以參考下

 前言

面試題:vuecreatedwatch(immediate: true)computed的執(zhí)行順序是啥?

先看個(gè)簡單的例子:

// main.js
import Vue from "vue";

new Vue({
  el: "#app",
  template: `<div>
    <div>{{computedCount}}</div>
  </div>`,
  data() {
    return {
      count: 1,
    }
  },
  watch: {
    count: {
      handler() {
        console.log('watch');
      },
      immediate: true,
    }
  },
  computed: {
    computedCount() {
      console.log('computed');
      return this.count + 1;
    }
  },
  created() {
    console.log('created');
  },
});

當(dāng)前例子的執(zhí)行順序?yàn)椋?code>watch --> created --> computed。

為什么?

new Vue的實(shí)例化過程中,會(huì)執(zhí)行初始化方法this._init,其中有代碼:

Vue.prototype._init = function (options) {
    // ...
    initState(vm);
    // ...
    callHook(vm, 'created');
    // ...
    if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
}

function initState (vm) {
  vm._watchers = [];
  var opts = vm.$options;
  if (opts.props) { initProps(vm, opts.props); }
  if (opts.methods) { initMethods(vm, opts.methods); }
  if (opts.data) {
    initData(vm);
  } else {
    observe(vm._data = {}, true /* asRootData */);
  }
  if (opts.computed) { initComputed(vm, opts.computed); }
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch);
  }
}

猛一看代碼,是不是發(fā)現(xiàn)先執(zhí)行的initComputed(vm, opts.computed),然后執(zhí)行initWatch(vm, opts.watch),再執(zhí)行callHook(vm, 'created'),那為啥不是computed --> watch --> created呢?

不要著急,聽我娓娓道來。

1、關(guān)于initComputed

const computedWatcherOptions = { lazy: true }
function initComputed (vm: Component, computed: Object) {
  // $flow-disable-line
  const watchers = vm._computedWatchers = Object.create(null)
  // computed properties are just getters during SSR
  const isSSR = isServerRendering()

  for (const key in computed) {
    const userDef = computed[key]
    const getter = typeof userDef === 'function' ? userDef : userDef.get
    // ...
    if (!isSSR) {
      // create internal watcher for the computed property.
      watchers[key] = new Watcher(
        vm,
        getter || noop,
        noop,
        computedWatcherOptions
      )
    }

    // component-defined computed properties are already defined on the
    // component prototype. We only need to define computed properties defined
    // at instantiation here.
    if (!(key in vm)) {
      defineComputed(vm, key, userDef)
    } else if (process.env.NODE_ENV !== 'production') {
        // ...
    }
  }
}

在通過initComputed初始化計(jì)算屬性的時(shí)候,通過遍歷的方式去處理當(dāng)前組件中的computed。首先,在進(jìn)行計(jì)算屬性實(shí)例化的時(shí)候,將{ lazy: true }作為參數(shù)傳入,并且實(shí)例化的Watcher中的getter就是當(dāng)前例子中的computedCount函數(shù);其次,通過defineComputed(vm, key, userDef)的方式在當(dāng)前組件實(shí)例vm上為key進(jìn)行userDef的處理。具體為:

export function defineComputed (
  target: any,
  key: string,
  userDef: Object | Function
) {
  const shouldCache = !isServerRendering()
  if (typeof userDef === 'function') {
    sharedPropertyDefinition.get = shouldCache
      ? createComputedGetter(key)
      : createGetterInvoker(userDef)
    sharedPropertyDefinition.set = noop
  }
  // ...
  Object.defineProperty(target, key, sharedPropertyDefinition)
}

function createComputedGetter (key) {
  return function computedGetter () {
    const watcher = this._computedWatchers && this._computedWatchers[key]
    if (watcher) {
      if (watcher.dirty) {
        watcher.evaluate()
      }
      if (Dep.target) {
        watcher.depend()
      }
      return watcher.value
    }
  }
}

從以上可以看出,這里通過Object.defineProperty(target, key, sharedPropertyDefinition)的方式,將函數(shù)computedGetter作為get函數(shù),只有當(dāng)對(duì)key進(jìn)行訪問的時(shí)候,才會(huì)觸發(fā)其內(nèi)部的邏輯。內(nèi)部邏輯watcher.evaluate()為:

evaluate () {
    this.value = this.get()
    this.dirty = false
}

get中有主要邏輯:

value = this.getter.call(vm, vm)

這里的this.getter就是當(dāng)前例子中的:

computedCount() {
  console.log('computed');
  return this.count + 1;
}

也就是說,只有當(dāng)獲取computedCount的時(shí)候才會(huì)觸發(fā)computed的計(jì)算,也就是在進(jìn)行vm.$mount(vm.$options.el)階段才會(huì)執(zhí)行到console.log('computed')。

2、關(guān)于initWatch

function initWatch (vm: Component, watch: Object) {
  for (const key in watch) {
    const handler = watch[key]
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
        createWatcher(vm, key, handler[i])
      }
    } else {
      createWatcher(vm, key, handler)
    }
  }
}
function createWatcher (
  vm: Component,
  expOrFn: string | Function,
  handler: any,
  options?: Object
) {
  if (isPlainObject(handler)) {
    options = handler
    handler = handler.handler
  }
  if (typeof handler === 'string') {
    handler = vm[handler]
  }
  return vm.$watch(expOrFn, handler, options)
}

在通過initWatch初始化偵聽器的時(shí)候,如果watch為數(shù)組,則遍歷執(zhí)行createWatcher,否則直接執(zhí)行createWatcher。如果handler是對(duì)象或者字符串時(shí),將其進(jìn)行處理,最終作為參數(shù)傳入vm.$watch中去,具體為:

Vue.prototype.$watch = function (
    expOrFn: string | Function,
    cb: any,
    options?: Object
  ): Function {
    const vm: Component = this
    if (isPlainObject(cb)) {
      return createWatcher(vm, expOrFn, cb, options)
    }
    options = options || {}
    options.user = true
    const watcher = new Watcher(vm, expOrFn, cb, options)
    if (options.immediate) {
      try {
        cb.call(vm, watcher.value)
      } catch (error) {
        handleError(error, vm, `callback for immediate watcher "${watcher.expression}"`)
      }
    }
    return function unwatchFn () {
      watcher.teardown()
    }
  }

這里獲取到的options中會(huì)有immediate: true的鍵值,同時(shí)通過options.user = true設(shè)置usertrue,再將其作為參數(shù)傳入去進(jìn)行Watcher的實(shí)例化。

當(dāng)前例子中options.immediatetrue,所以會(huì)執(zhí)行cb.call(vm, watcher.value),也就是以vm為主體,立刻執(zhí)行cb。當(dāng)前例子中cb就是handler

handler() {
    console.log('watch');
},

這里就解釋了當(dāng)前例子中console.log('watch')是最先執(zhí)行的。

然后,執(zhí)行完initComputedinitWatch以后,就會(huì)通過callHook(vm, 'created')執(zhí)行到生命周期中的console.log('created')了。

最后通過vm.$mount(vm.$options.el)進(jìn)行頁面渲染的時(shí)候,會(huì)先去創(chuàng)建vNode,這時(shí)就需要獲取到computedCount的值,進(jìn)而觸發(fā)其get函數(shù)的后續(xù)邏輯,最終執(zhí)行到console.log('computed')

附:為什么vue中的watch在mounted之后執(zhí)行

首先,在調(diào)用mounted的時(shí)候,會(huì)進(jìn)入到defineReactive函數(shù),然后調(diào)用函數(shù)里面的set方法,將mounted中賦的新的值給傳遞過去,并通過調(diào)用dep.notify( )把消息發(fā)送給訂閱者,繼而更新訂閱者的列表

后面才開始渲染watch進(jìn)入Watcher的class

總結(jié)

關(guān)于vuecreatedwatch的執(zhí)行順序相對(duì)比較簡單,而其中computed是通過Object.defineProperty為當(dāng)前vm進(jìn)行定義,再到后續(xù)創(chuàng)建vNode階段才去觸發(fā)執(zhí)行其get函數(shù),最終執(zhí)行到計(jì)算屬性computed對(duì)應(yīng)的邏輯。

到此這篇關(guān)于vue中created、watch和computed執(zhí)行順序詳解的文章就介紹到這了,更多相關(guān)vue created、watch和computed執(zhí)行順序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vant-ui組件庫中如何修改NavBar導(dǎo)航欄的樣式

    vant-ui組件庫中如何修改NavBar導(dǎo)航欄的樣式

    這篇文章主要介紹了vant-ui組件庫中如何修改NavBar導(dǎo)航欄的樣式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • vue router2.0二級(jí)路由的簡單使用

    vue router2.0二級(jí)路由的簡單使用

    這篇文章主要為大家詳細(xì)介紹了vue router2.0二級(jí)路由的簡單使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • vue項(xiàng)目中的webpack-dev-sever配置方法

    vue項(xiàng)目中的webpack-dev-sever配置方法

    下面小編就為大家分享一篇vue項(xiàng)目中的webpack-dev-sever配置方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • 詳解vue渲染函數(shù)render的使用

    詳解vue渲染函數(shù)render的使用

    本篇文章主要介紹了vue渲染函數(shù)render的使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • 淺析Vue中method與computed的區(qū)別

    淺析Vue中method與computed的區(qū)別

    在new Vue的配置參數(shù)中的computed和methods都可以處理大量的邏輯代碼,但是什么時(shí)候用哪個(gè)屬性,要好好區(qū)分一下才能做到正確的運(yùn)用vue。這篇文章主要介紹了Vue中method與computed的區(qū)別,需要的朋友可以參考下
    2018-03-03
  • 使用element ui中el-table-column進(jìn)行自定義校驗(yàn)

    使用element ui中el-table-column進(jìn)行自定義校驗(yàn)

    這篇文章主要介紹了使用element ui中el-table-column進(jìn)行自定義校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • vue中4個(gè)自定義指令講解及實(shí)例用法

    vue中4個(gè)自定義指令講解及實(shí)例用法

    在本篇文章里小編給大家整理了一篇關(guān)于vue中4個(gè)自定義指令講解及實(shí)例用法,有興趣的朋友們可以跟著學(xué)習(xí)下。
    2021-12-12
  • vuex使用及持久化方式

    vuex使用及持久化方式

    這篇文章主要介紹了vuex使用及持久化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Vue實(shí)現(xiàn)點(diǎn)擊顯示不同圖片的效果

    Vue實(shí)現(xiàn)點(diǎn)擊顯示不同圖片的效果

    這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)點(diǎn)擊顯示不同圖片的效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • vue項(xiàng)目中vue.config.js文件詳解

    vue項(xiàng)目中vue.config.js文件詳解

    vue.config.js?是一個(gè)可選的配置文件,如果項(xiàng)目的?(和?package.json?同級(jí)的)?根目錄中存在這個(gè)文件,那么它會(huì)被?@vue/cli-service?自動(dòng)加載,這篇文章主要介紹了vue項(xiàng)目中vue.config.js文件的介紹,需要的朋友可以參考下
    2024-02-02

最新評(píng)論