面试问题:created生命期中2次修改代码,会开启几回页面更新?

一、同步

先举一个简单同步事例:

new Vue({
  el: "#app",
  template: `<div>
    <div>{{count}}</div>
  </div>`,
  data() {
    return {
      count: 1,
    }
  },
  created() {
    this.count = 2;
    this.count = 3;
  },
});

created生命期中,根据this.count = 2this.count = 3的形式将this.count再次取值。

这儿立即抛出去回答:3D渲染一次。


为何?

这一与数据的响应式网站解决相关,首先看响应式网站解决的思路:

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  // 关键:创建一个上传者案例
  const dep = new Dep()

  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }

  let childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        // 关键:开展现阶段已经计算出来的3D渲染Watcher的搜集
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
      const value = getter ? getter.call(obj) : val
      /* eslint-disable no-self-compare */
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      /* eslint-enable no-self-compare */
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
      // #7981: for accessor properties without setter
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      // 关键:当数据信息变化时,上传者案例dep会通告收集的watcher进行更新
      dep.notify()
    }
  })
}

在数据响应式网站解决环节,会创建对象一个上传者dep,同时通过Object.defineProperty方式为现阶段数据定义getset函数公式。在形成虚似vNode的时期,会开启get函数中将进行现阶段已经计算出来的3D渲染Watcher的搜集,这时,上传者depsubs时会多一个3D渲染Watcher案例。在数据发生变化情况下,会开启set函数公式,通告上传者depsubs里的watcher进行更新。

对于数据修改会开启几回升级,就与当前上传者depsubs中搜集了几回3D渲染watcher相关了,再看一遍watcher收集和created实行中间顺序:

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

我们都知道在initState(vm)环节对数据进行响应式网站解决,可是这时上传者depsubs或是空数组。当实行callHook(vm, 'created')时,会实行this.count = 2this.count = 3的思路,也确实会开启set函数中的dep.notify通告收集的watcher进行更新。可是,这时depsubs是空数组,等同于什么也没做。

只会在vm.$mount(vm.$options.el)实施过程中,形成虚似vNode的时候才能开展3D渲染Watcher搜集,这时,depsubs才不为空。最后,根据vm.$mount(vm.$options.el)展开了界面的一次3D渲染,并没有由于this.count=2或是this.count=3而开启多余页面更新。

简而言之,便是created钩子函数里的逻辑实行要在3D渲染watcher搜集以前实施的,因此未造成由于数据变化而造成的页面更新。

二、多线程的

同步情景讲完了,咱们就举一个多线程的事例:

new Vue({
  el: "#app",
  template: `<div>
    <div>{{count}}</div>
  </div>`,
  data() {
    return {
      count: 1,
    }
  },
  created() {
    setTimeout(() => {
      this.count = 2;
    }, 0)
    setTimeout(() => {
      this.count = 3;
    }, 0)
  },
});

created生命期中,根据多线程的形式实行this.count = 2this.count = 3的形式将this.count再次取值。

这儿立即抛出去回答:初次3D渲染一次,由于数据变化所导致的页面更新2次。


为何?

这个我与eventLoop事件循环体制相关了,我们都知道javascript是一个单核实行的表达,在我们根据new Vue创建对象的过程当中,会实行初始化方法this._init方式,正式开始Vue最底层的解决逻辑性。在遇到setTimeout异步操作时,会把其送入到多线程序列中来,等候现阶段同歩任务执行完之后再去多线程序列中取出队首原素开展实行。

现阶段例子中,在initState(vm)环节对数据进行响应式网站解决。当实行callHook(vm, 'created')时,会把this.count = 2this.count = 3的思路送入到多线程序列等候实行。执行vm.$mount(vm.$options.el)的过程中需要去形成虚似vNode,从而开启get函数的3D渲染Watcher搜集,这时,depsubs里就有了一个3D渲染watcher

等初次页面渲染完成以后,想去实行this.count=2的思路,数据库的改动会开启set函数中的dep.notify,这时上传者depsubs不为空,也会引起界面的升级。同样,this.count=3会重新造成网页页面数据信息的更新。换句话说,初次3D渲染一次,由于this.count=2this.count=3还会造成页面更新2次。

三、额外

假如我更改数值和data中界定数值一致呢?

new Vue({
  el: "#app",
  template: `<div>
    <div>{{count}}</div>
  </div>`,
  data() {
    return {    count: 1,
    }
  },
  created() {
    setTimeout(() => {
      this.count = 1;
    }, 0)
  },
});

这时候,在开启set的思路中,会当实行到if (newVal === value || (newVal !== newVal && value !== value)) { return }的思路,不容易再执行到dep.notify,这类场景中数据库的数据信息也不会造成界面的再度升级。

汇总

从生命期created和页面渲染的顺序,Object.defineProperty开启getset函数的原理,及其eventLoop事件循环体制下手,来分析created中2次数据修改会开启几回页面更新问题便会清楚许多。

声明:本文仅供个人学习使用,来源于互联网,本文有改动,本文遵循[BY-NC-SA]协议, 如有侵犯您的权益,请联系本站,本站将在第一时间删除。谢谢你

原文地址:created生命期中2次修改代码,会开启几回页面更新?