• vue响应式原理


    vue响应式原理

    一、响应式框架

    • 侦听数据变化(数据拦截)
    • 收集谁依赖了数据,比如视图、计算属性等(订阅更新)
    • 数据发生变化,通知依赖进行更新(派发更新)

    操作DOM带来的问题

    • 需要操作多个DOM元素,非常不方便
    • 每一次数据变化都要操作DOM
    • 频繁操作DOM带来的性能问题
    • 思路:不在逻辑计算过程中操作DOM,尽量减少DOM操作

    MVVM模式

    • Android的消息队列模型
    • RxJava的响应式编程
    • AngularJS等

    Vue不支持IE8及以下浏览器是由于低版本浏览器不支持defineProperty是ES5新方法

    二、Vue如何实现响应式框架

    关于对象

    1. 对象属性包括数据属性和访问器属性
    2. 数据属性描述符:configurable、enumerable、writable、value
    3. 访问器属性描述符:configurable、enumerable、get、set
    4. 属性描述符属于内部特性,用于描述属性行为,无法直接访问,但可通过defineProperty进行修改
    5. 访问器属性没有数据值,取而代之的是get、set函数
    6. 将数据属性改为访问器属性,使用getter和setter来拦截数据的访问和修改是响应式的基石

    关于数据拦截

    组件init阶段,Vue的data属性会被Observe类reactive化,即加上getter和setter函数,并建立依赖Dep

    function observe(obj){
        if(!obj || typeof obj !== object){
            return
        }
        Object.keys(obj).forEach(key=>{
            defineReactive(obj,key,obj[key])
        })
        function defineReactive(obj,key,value){
            observe(value)
            Object.defineProperty(obj,key,{
                enumerable:true,
                configurable:true,
                get:function(){
                    // 依赖收集
                    return value
                },
                set:function(){
                    observe(newValue)
                    if(newValue !== value){
                        value = newValue
                        //派发更新
                    }
                }
            })
        }
    }
    

    三、Vue如何保证UI更新?

    对象变更检测

    1. 由于javascript的限制,目前Vue无法检测到对象属性的添加或删除(必须注册到Vue的data中)
    2. 根级别的响应式属性:不允许动态添加、删除
    3. 嵌套对象的响应式属性:允许添加、删除,但是需要通过Vue提供的方法进行操作,通过Vue将属性修改为响应式属性
    // 动态添加响应式属性
    Vue.set(vm.person,'age',18)
    // 删除响应式属性
    Vue.delete(vm.person,'name')
    // 不能再根级别添加响应式属性
    Vue.set(vm,'count',12)
    

    特殊的数组的更新检测

    1. 所有的对象上都有Object.defineProperty方法,可以通过get&set方法实现数据劫持,但是数组没有这两个方法
    2. Vue将被侦听的数组的变异方法进行了包裹,使得他们也能触发视图更新
    push、pop、shift、unshift、slice、sort、reverse
    
    1. 数组替换也能通知到Vue,从而触发视图更新

    Vue无法检测到的数组更新

    1. 通过索引直接修改数组项
    // 错误方法:
    vm.items[index] = newVal
    // 修正方法:
    Vue.set(vm.items,index,newVal)  or vm.items.splice(index,1,newVal)
    
    1. 修改数组的长度
    // 错误方法:
    vm.items.length
    // 修正方法:
    vm.items.splice(items.length)
    

    JavaScript中的事件循环

    宏任务与微任务

    1. 宏任务和微任务都是异步任务
    2. 宏任务和微任务都会被注册到两个不同的队列中
    3. 宏任务队列不是一次性清空执行,而是执行一个宏任务后,去清空执行一次微任务队列
    4. 在执行微任务的过程中加入微任务队列的微任务,也会在当前循环中执行
    常见宏任务:
    setTimeout、setInterval、setImmediate、script、MessageChannel
    常见微任务:
    Promise、MutationObserver、Object.observe(废弃)、process.nextTick(node)
    

    DOM更新也是一个微任务

    异步刷新机制

    1. 只要侦听到数据变化,Vue将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watch被多次触发,只会只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和DOM操作是非常重要的。然后在下一个事件循环tic中,Vue刷新队列并执行实际(已去重)工作。
    2. Vue在内部对异步队列尝试使用原生Promise.then、MutationObserver和setImmediate,如果执行环境不支持,则会采用setTimeout(fn,0)代替。

    异步队列

    1. 所有同步任务都在主线程上执行,形成一个执行栈
    2. 主线程之外,还存在一个或多个任务队列,主要异步任务有了运行结果,就在异步队列中放置一个事件
    3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
    4. 主线程不断重复上面第3步
  • 相关阅读:
    maven配置checkstyle插件对代码规范进行静态检查
    maven项目使用jacoco插件检测代码覆盖率详细配置
    bzoj4390[Usaco2015 dec]Max Flow*
    bzoj4393[Usaco2015 Dec]Fruit Feast*
    bzoj4397[Usaco2015 dec]Breed Counting*
    bzoj4396[Usaco2015 dec]High Card Wins*
    bzoj4395[Usaco2015 dec]Switching on the Lights*
    bzoj1725[Usaco2006 Nov]Corn Fields牧场的安排*
    bzoj1231[Usaco2008 Nov]mixup2 混乱的奶牛*
    bzoj3396[Usaco2009 Jan]Total flow 水流*
  • 原文地址:https://www.cnblogs.com/nanhuaqiushui/p/13378421.html
Copyright © 2020-2023  润新知