Добавьте эту статью в избранное, перестаньте говорить о "краже данных"

JavaScript Vue.js
Добавьте эту статью в избранное, перестаньте говорить о "краже данных"

Недавно я связался с несколькими интервьюерами, и когда я спросил, «как Vue реализует двустороннюю привязку данных», я выпалил «перехват данных», и что дальше? Тогда нет ╮(╯_╰)╭. Верно, что «перехват данных» — это основа, но это далеко не тот ответ, который хочет услышать интервьюер, лучше потратить десять минут на чтение этой статьи и ответить на него в следующий раз.

Сама "двусторонняя привязка"

Чтобы ответить на вопрос, сначала поймите вопрос:двусторонняя привязка данныхЭто режим В веб-контексте он обычно относится к автоматической синхронизации данных из dom с объектами JS. DOM и JS изолированы в двух разных средах выполнения, и им необходимо передавать друг другу императивные команды.DOM-интерфейсКоммуникация: DOM должен правильно запускать события и передавать информацию JS-программе, а JS также должен сознательно вызывать соответствующий интерфейс для изменения содержимого DOM после изменения состояния. Такой подход вызывает две проблемы:

  1. Управление состоянием и представление — это два отдельных набора логики, которые необходимо синхронизировать, что требует больших затрат на разработку.
  2. Спецификация DOM определяет множество интерфейсов, и есть проблемы с совместимостью, что требует больших затрат на изучение.

Двусторонняя привязка инкапсулирует процесс синхронизации данных из DOM в JS или из JS в DOM с помощью различных конструкций и инкапсулирует его в самом фреймворке.Код верхнего уровня отделен от зависимости от нижележащего интерфейса, и ему нужно только сосредоточиться на логике управления состоянием.

Object.defineProperty

Первый вопрос, который мы хотим обсудить, — как обнаружить изменения в свойствах объекта JS? Самый простой и грубый метод — это «грязная проверка», которая используется в более старых версиях Angular для запуска «грязной проверки» после различных событий, которые могут вызвать изменения состояния. Этот метод интуитивно понятен, но при его реализации необходимо учитывать множество моментов:

  1. В процессе грязной проверки могут инициироваться новые изменения данных, и возникает бесконечный цикл.
  2. Реализация грязной проверки должна сохранять копию старых и новых данных.
  3. Грязные проверки должны предсказывать все возможные тайминги, вызывающие изменения состояния, а это означает, что некоторые нативные интерфейсы должны быть обернуты (в том числеsetTimeout,requestNextAnimationFrameЖдать)
  4. ...

Vue использует интерфейс метапрограммированияObject.definePropertyосуществленный. Когда компонент инициализируется, интерфейс будет вызываться для обертывания свойств объекта какget,setфункция, которая «встраивает» код в поведение «Получить», «Изменить». Взгляните на простой пример и почувствуйте это интуитивно:

const person = {};

// 嘿嘿,谁都改不了我的名字
Object.defineProperty(person, 'name', {
	get() {
		return 'van';
	},
	set(v) {
		console.log('they want change my name');
	}
});

console.log(person.name);
// van
person.name = 'tec';
// they want change my name
console.log(person.name);
// van

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

Object.definePropertyЭто просто решает проблему, как инициировать уведомление после изменения состояния.Кого следует уведомлять? Кого волнует, что эти свойства изменились? В Vue используйтеDepРазделяет процесс определения отношения между зависимым и зависимым. Проще говоря:

  • Первый шаг, черезObserverПредоставленный интерфейс проходит через объект состояния и привязывает выделенный объект к каждому свойству и подсвойству объекта.Depобъект. Объект состояния здесь в основном относится к компонентам в компоненте.dataАтрибуты.

  • Второй шаг — создать три типа наблюдателей:

    1. передачаinitComputedБудуcomputedатрибуты преобразуются вwatcherпример
    2. передачаinitWatchметод, будетwatchконфиг переводится какwatcherпример
    3. передачаmountComponentметод, дляrenderсвязывание функцийwatcherпример
  • Третий шаг, после изменения состояния, триггерdep.notify()функция, которая запускает дальнейшиеWatcherобъектupdateФункция, выполняющая пересчет наблюдателя.

Соответствует следующему рисунку:

data.png

Обратите внимание, что в компоненте Vuerenderфункцию, мы можем просто думать о ней как о специальнойcomputedфункция в соответствующемWatcherКогда объект изменяется, запускается выполнение рендеринга для создания новой структуры виртуального дома, которая затем передается Vue для сравнения и обновления представления.

Эпилог

На этом статья заканчивается. Для получения дополнительной информации вы можете посмотреть исходный код. Шаблоны проектирования в коде очень достойны изучения.

Vue использует перехват данных в качестве базовой поддержки и разрабатывает сложное решение для управления зависимостями, чтобы отделить зависимости. Однако схема захвата данных также имеет свои болевые точки, которые трудно решить:

  1. Может применяться только к простым объектам
  2. Недействительно для массивов, поэтому вам нужно обернуть метод массива
  3. Отправной точкой захвата атрибута является «изменение», поэтому vue не может легко получить доступ к «неизменяемому» режиму.