Прокси реализует практику vue MVVM

Vue.js MVVM

Только что прошла конференция vueconf (2018hangzhou), автор vue You Da показал нам прогресс vue 3.0 и внес некоторые изменения в vue 3.0, самое ожидаемое из которых - переписывание механизма мониторинга данных.

Просмотрите двустороннюю привязку данных vue2.x.

Когда дело доходит до двусторонней привязки данных Vue, первое, о чем мы можем подумать, это ES5.Object.defineProperty, используя переопределенные свойстваget,set, мы можем завершить мониторинг захвата данных, использовать режим наблюдателя и уведомлять подписчиков об обновлении статуса при изменении данных.
мы стремимся кObserverЧасть наблюдателя написала простой код следующим образом:


function Observer (data) {
  this.data = data
  this.walk(data)
}
Observer.prototype = {
  walk: function (data) {
    let me = this
    Object.keys(data).forEach(function (key) {
      me.convert(key, data[key])
    })
  },
  
  convert: function (key, val) {
    this.defineReactive(this.data, key, val)
  },

  defineReactive: function (data, key, val) {
    let dep = new Dep()
    let childObj = observe()

    Object.defineProperty(data, key, {
      enumerable: true,
      configurable: false,
      get: function () {
        if (Dep.target) {
            dep.depend()  // 添加订阅者
        }
        return val
      },
      set: function (newVal) {
        if (newVal === val)  return

        val = newVal
        childObj = observe(newVal)
        dep.notify()  // 通知订阅器
      }
    })
  }
}
function observe (value, vm) {
  if (!value || typeof value !== 'object') {
      return
  }

  return new Observer(value)
}

В приведенном выше коде мы определяемObserverКонструктор, наблюдатель. использоватьObject.definePropertyМониторинг данных будем производить по всем атрибутам (в т.ч. субатрибутам) входящего объекта, а вgetметод, добавьте подписку на подписчика. Как только свойство изменится, уведомите подписчиков.

Код подписчика Dep, инструкции Compile и подписчика Watcher больше не анализируется, общую структуру mvvm можно увидеть на следующем рисунке.

Весь процесс состоит из четырех частей: наблюдатель, подписчик, подписчик и командир, каждая из которых выполняет свои обязанности.

Краткое введение в прокси

Прокси — это недавно добавленный конструктор в ES6. Его можно понимать как настройку уровня «перехвата» перед целевым объектом. Весь доступ к объекту из внешнего мира должен проходить через этот уровень перехвата. Поэтому он предоставляет механизм для доступа к перезаписи фильтра. Первоначальное значение Proxy — прокси, и здесь мы можем понимать его как «прокси» для некоторых операций.

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`proxy get ${key}`)
    return Reflect.get(target, key, receiver)
  },
  set: function (target, key, value, receiver) {
    console.log(`proxy set ${key}`)
    return Reflect.set(target, key, value, receiver)
  }
})

Приведенный выше код устанавливает уровень перехвата пустого объекта, мы можем передать второй параметр Proxy.handlerОбъект, в котором можно определить поведение перехвата.
существуетgetа такжеset, мы использовалиReflect.Reflectобъект сProxyКак и объекты, это также новый API, предоставляемый ES6 для управления объектами.Reflectметоды объекта иProxyМетоды объекта соответствуют взаимно однозначному, напримерProxyперехват методаtargetПоведение присвоения свойств объектам. он принимаетReflect.setМетоды присваивают значения свойствам объекта, гарантируя, что исходное поведение выполняется до развертывания дополнительных функций.
По приведенному выше коду пишем тестовый код:

obj.text = 'hello world!' 
// proxy set text
var _text = obj.text
// proxy get text

Наблюдатель переопределения прокси

Используя вышеизложенноеProxyНекоторые особенности, модифицируем код следующим образом:

function observe (value, vm) {
  if (!value || typeof value !== 'object') {
    return
  }

  let dep = new Dep()
  return new Proxy(value, {
    get: function (target, key, receiver) {
      if (Dep.target) {
        dep.depend()
      }
      return Reflect.get(target, key, receiver)
    },
    set: function (target, key, value, receiver) {
      dep.notify()
      return Reflect.set(target, key, value, receiver)
    }
  })
}

Мы заменяем входящий объект напрямую наProxyобъект, вводhandlerизgetа такжеsetЛогика добавления подписчика и подписчика уведомлений остается прежней.
Никаких других избыточных суждений не было сделано в течение всего процесса.Поскольку Vue3.0 еще не выпущен, нет фактического исходного кода для справки, поэтому вышеизложенное является просто простой версией личной реализации (полный код). Примените весь mvvm к html, после запуска будет следующий эффект (без gif, просто сделайте его):

Преимущества переопределения механизма мониторинга данных

  1. сдатьсяObject.defineProperty, основанный на механизме прокси-наблюдателя для полного охвата языков и повышения производительности. Благодаря изменениям оптимизации других методов vue3.0 может удвоить скорость/половину использовать память;
  2. ObserverМодули будут доступны по отдельности в виде библиотеки.

возможные проблемы

К сожалению, ES6ProxyНевозможно перенести в ES5, поэтому он не будет поддерживаться IE. Для этой проблемы Vue3.0 даст совместимое решение для IE11, то есть под IE11 все еще используетсяObject.definePropertyмеханизм.

использованная литература

Начало работы с ECMAScript 6 (Ифэн Жуань):es6.ruanyifeng.com/#docs/proxy
План обновления vue 3.0: быстрее, меньше, проще для разработчиков:Woohoo.OSCHINA.net/news/101906…
Почему Proxy может оптимизировать механизм мониторинга данных vue:nuggets.capable/post/684490…