vue面试created中两次数据修改会触发几次页面更新详解

 更新时间:2022年12月22日 10:56:58   作者:qb  
这篇文章主要为大家介绍了vue面试created中两次数据修改会触发几次页面更新问题解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

面试题:

created生命周期中两次修改数据,会触发几次页面更新?

一、同步的

先举个简单的同步的例子:

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重新赋值。

这里直接抛出答案:渲染一次。

为什么? 

这个与数据的响应式处理有关,先看响应式处理的逻辑:

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) {
        // 重点:进行当前正在计算的渲染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函数中会进行当前正在计算的渲染Watcher的收集,此时,发布者depsubs中会多一个渲染Watcher实例。在数据发生变化的时候,会触发set函数,通知发布者depsubs中的watcher进行更新。

至于数据修改会触发几次更新,就与当前发布者depsubs中收集了几次渲染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的时候才会进行渲染Watcher收集,此时,depsubs才不为空。最终,通过vm.$mount(vm.$options.el)进行了页面的一次渲染,并未因为this.count=2或者this.count=3而触发多余的页面更新。

简言之,就是created钩子函数内的逻辑的执行是在渲染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重新赋值。

这里直接抛出答案:首次渲染一次,因为数据变化导致的页面更新两次。

为什么?

这个就与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函数的渲染Watcher收集,此时,depsubs中就有了一个渲染watcher

等首次页面渲染完成以后,会去执行this.count=2的逻辑,数据的修改会触发set函数中的dep.notify,此时发布者depsubs不为空,会引起页面的更新。同理,this.count=3会再次引起页面数据的更新。也就是说,首次渲染一次,因为this.count=2this.count=3还会导致页面更新两次。

三、附加

如果我改变的值和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中两次数据修改会触发几次页面更新的问题就会清晰很多。

以上就是vue面试created中两次数据修改会触发几次页面更新详解的详细内容,更多关于vue created数据修改页面更新的资料请关注脚本之家其它相关文章!

相关文章

  • vue3中使用jsx的实现步骤

    vue3中使用jsx的实现步骤

    本文主要介绍了vue3中使用jsx的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Vue批量图片显示时遇到的路径被解析问题

    Vue批量图片显示时遇到的路径被解析问题

    这篇文章主要介绍了Vue批量图片显示时遇到的路径被解析问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • vue+elementui实现下拉表格多选和搜索功能

    vue+elementui实现下拉表格多选和搜索功能

    这篇文章主要为大家详细介绍了vue+elementui实现下拉表格多选和搜索功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Vue项目打包(build)时,自动打以时间命名的压缩包方式

    Vue项目打包(build)时,自动打以时间命名的压缩包方式

    这篇文章主要介绍了Vue项目打包(build)时,自动打以时间命名的压缩包方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • 浅谈vue的踩坑路

    浅谈vue的踩坑路

    下面小编就为大家带来一篇浅谈vue的踩坑路。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • Vue之使用mockjs生成模拟数据案例详解

    Vue之使用mockjs生成模拟数据案例详解

    这篇文章主要介绍了Vue之使用mockjs生成模拟数据案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • Vue不能下载xls以及文件乱码问题解决

    Vue不能下载xls以及文件乱码问题解决

    最近工作中遇到了一些问题,通过查找相关资料终于找到了相关的解决方法,这篇文章主要给大家介绍了关于Vue不能下载xls以及文件乱码问题解决的相关资料,需要的朋友可以参考下
    2022-04-04
  • vue实现父组件获取子组件的方法或属性值详解

    vue实现父组件获取子组件的方法或属性值详解

    这篇文章主要介绍了vue实现父组件获取子组件的方法或属性值详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • ElementUI组件Dialog弹窗再次打开表单仍显示上次数据的问题

    ElementUI组件Dialog弹窗再次打开表单仍显示上次数据的问题

    这篇文章主要介绍了ElementUI组件Dialog弹窗再次打开表单仍显示上次数据的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • vue中如何使用lodash的debounce防抖函数

    vue中如何使用lodash的debounce防抖函数

    防抖函数 debounce 指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次,在Vue中使用防抖函数可以避免在频繁触发的事件中重复执行操作,这篇文章主要介绍了vue中使用lodash的debounce防抖函数,需要的朋友可以参考下
    2024-01-01

最新评论