2021年7月4日星期日

vue3响应式模式设计原理

vue3响应式模式设计原理

为什么要关系vue3的设计原理?了解vue3构建原理,将有助于开发者更快速上手Vue3;同时可以提高Vue调试技能,可以快速定位错误

1.vue3对比vue2

  1. vue2的原理是通过 Object.defineProperty() 来劫持各个属性,在数据变动时发布消息给订阅者,触发相应的监听回调。

defineProperty不具备监听数组的能力,无法检测到对象属性的添加和删除,只有在初始化实例时对data对象转换响应式,后面新增的需要手动转换,深度监听需要一次性递归,性能不好

  1. vue3的原理基于ES6新特性Proxy对象代理

可以监听原生数组,不需要一次性遍历data的属性,提高性能,vue3将响应式模块分离封装,可以随时对对象进行代理,为组合式api提供了可能,因为Proxy是ES6新增的属性,有些浏览器还不支持,只能兼容到IE11

可以看出vue3的响应式给开发者带来极大的便利,深层次的对象监听中,再也不怕层级问题或者新增属性问题带来的监听失效

好消息:2021.05.19微软官方博客发布 公告 表示:2022-06-15微软将正式不再支持IE,现在我们有理由让客户去下载谷歌浏览器了

2.针对编程语言的编程

vue的响应式设计,使用了ES6的新特性,如:Proxy,WeakMap,Reflect…,从而对javascrip进行了编程

  • 步骤一: 追踪一个变量
const price = 5
let quantity = 2
let total = 0
let storage = 0

// Set对象是值的集合 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
let dep = new Set() 

let effect1 = () => { total = price * quantity }
let effect2 = () => { storage = 100 - quantity }

function track() {
  dep.add(effect1)
  dep.add(effect2)
}
function trigger() { dep.forEach(effect => effect()) }

track()
effect1()
effect2()

// 运行
> total
10
> storage
98
> quantity = 5
5
> total
10
> storage
98
> trigger()
undefined
> total
25
> storage
95
  • 步骤二: 追踪对象中的属性
let product = { price: 5, quantity: 2 }
let total = 0

// Map 对象保存键值对。任何值都可以作为一个键或一个值
const depsMap = new Map() 

let effect = () => {
  total = product.price * product.quantity
}

function track(key) {
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  dep.add(effect)
}
function trigger(key) {
  let dep = depsMap.get(key)
  if (dep) {
    dep.forEach(effect => effect())
  }
}

track('price')
track('quantity')
effect()

// 运行
> total
10
> product.quantity = 8
8
> total
10
> trigger('price')
undefined
> total
16
> product.quantity = 4
4
> total
16
> trigger('quantity')
undefined
> total
32
  • 步骤三: 追踪多个对象

tips: javascript 中垃圾回收的算法
JavaScript 中的内存管理是自动执行的,程序中不需要使用的数据或者程序无法访问到的数据都是垃圾,JavaScript会自己清理无用数据给其他数据清理空间
JavaScript 引擎中有一个后台进程称为垃圾回收器,它监视所有对象,并删除那些不可访问的对象。
一般来说没有被引用的对象就是垃圾,就是要被清除, 有个例外如果几个对象引用形成一个环,互相引用,但根访问不到它们,这几个对象也是垃圾,也要被清除。

// WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
// 原生的 WeakMap 持有的是每个键对象的"弱引用",不影响js垃圾回收机制。
const targetMap = new WeakMap()

let product = { price: 5, quantity: 2 }
let total = 0
let storage = { amount: 50, sale: 2 }
let remain = 48

let effect = () => {
  total = product.price * product.quantity
  remain = storage.amount - storage.sale
}

function track(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  dep.add(effect)
}
function trigger(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) return
  let dep = depsMap.get(key)
  if (dep) {
    dep.forEach(effect => effect())
  }
}

track(product, 'price')
track(storage, 'sale')
effect()

// 运行
> total
10
> remain
48
> product.price = 8
8
> storage.sale = 5
5
> total
10
> remain
48
> trigger(product, 'price')
undefined
> trigger(storage, 'sale')
undefined
> total
16
> remain
45

现在我们有了一套可以记录多个对象并根据对象变化追踪更新的机制,只要再加上自动记录以及自动触发更新就可以完善功能了

3.对象代理Proxy

  • 步骤一: Proxy和Reflect

tips:
1.Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。
Reflect对象有4个意义:
从Reflect对象上可以拿到语言内部的方法。
操作对象出现报错时返回false
让操作对象都变为函数式编程
保持和proxy对象的方法一一对象
2.Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

let product = { price: 5, quantity: 2 }

let proxiedProduct = new Proxy(product, {
  get(target, key, receiver) {
    console.log('get')
    // return target[key]
    // 注意我们的get有一个额外的参数receiver,我们将它作为参数发送到Reflect.get中。这确保了当我们的对象从另一个对象继承了值/函数时,可以使用正确的this。这就是为什么我们总是在代理内部使用Reflect。
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log('set')
    return Reflect.set(target, key, value, receiver)
  }
})

// 运行
> proxiedProduct.price = 8
set
< 8
> proxiedProduct.price
get
< 8
  • 步骤二: 进一步封装
const targetMap = new WeakMap()

function track(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  dep.add(effect)
}
function trigger(target, key) {
  let depsMap = targetMap.get(target)
  if (!depsMap) return
  let dep = depsMap.get(key)
  if (dep) {
    dep.forEach(effect => effect())
  }
}

function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      let result = Reflect.get(target, key, receiver)
      track(target, key)
      return typeof result === 'object' ? reactive(result) : result
    },
    set(target, key, value, receiver) {
      let oldValue = target[key]
      let result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key)
      }
      return result
    }
  }
  return new Proxy(target, handler)
}


let product = reactive({ price: 5, quantity: {a: 2} })
let total = 0
let effect = () => {
  total = product.price * product.quantity.a
}

effect()

// 运行
> total
< 10
> product.price = 8
< 8
> total
< 16
  • 步骤三: 移除非effect下的track,封装ref
let activeEffect = null

function track(target, key) {
  // 新增判断activeEffect,不是每次get都要track
  if (activeEffect) {
    let depsMap = targetMap.get(target)
    if (!depsMap) {
      targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) {
      depsMap.set(key, (dep = new Set()))
    }
    dep.add(activeEffect)
&nbs......

原文转载:http://www.shaoqun.com/a/846144.html

跨境电商:https://www.ikjzd.com/

转运中国:https://www.ikjzd.com/w/1549

extra:https://www.ikjzd.com/w/1736

tinypic:https://www.ikjzd.com/w/114


vue3响应式模式设计原理为什么要关系vue3的设计原理?了解vue3构建原理,将有助于开发者更快速上手Vue3;同时可以提高Vue调试技能,可以快速定位错误1.vue3对比vue2vue2的原理是通过Object.defineProperty()来劫持各个属性,在数据变动时发布消息给订阅者,触发相应的监听回调。defineProperty不具备监听数组的能力,无法检测到对象属性的添加和删除,只有
贝恩投资公司:https://www.ikjzd.com/w/1336
别再看仓库起火了!新政策让你连FBA仓库都进不去…:https://www.ikjzd.com/articles/15750
平台卖家纷纷转型丨大势所趋,还是恶性竞争所致? :https://www.ikjzd.com/articles/15751
亚马逊自动广告的误区,SP广告应该这样玩!:https://www.ikjzd.com/articles/15754
2018年全球购物App下载量报告出炉:Wish勇夺第一!:https://www.ikjzd.com/articles/15757
少妇口述:乱性丈夫将我拖进换妻游戏:http://lady.shaoqun.com/a/73636.html
学长让我夹震动上课 调教塞进去不准掉出来:http://lady.shaoqun.com/m/a/247737.html
情感口述:和父亲的情故事:http://lady.shaoqun.com/m/a/71481.html
这名女子被"房屋休克"折磨了一夜,但她别无选择,只能报警。邻居:你能拿我怎么办:http://lady.shaoqun.com/a/401725.html
疑似吴炮王致歉信:承认炮王愿意放弃研究:http://lady.shaoqun.com/a/401726.html
我昨晚被吵醒了!寒冷的冬天如何治疗皮肤干燥?五:http://lady.shaoqun.com/a/401727.html
该女子半夜被室友强奸。事后,这位女士嘲笑她的室友"太矮了"。:http://lady.shaoqun.com/a/401728.html

没有评论:

发表评论