Как реализована реактивность во Vue 2 и Vue 3 и в чем их отличия
Что проверяют
Понимает ли кандидат, почему во Vue 2 требовался Vue.set, и что именно изменил переход на Proxy, кроме слова «быстрее». Хороший ответ объясняет причины ограничений, а не перечисляет два имени API.
Как отвечать
Vue 2. При инициализации объект рекурсивно обходится, и каждое свойство переопределяется через Object.defineProperty с геттером и сеттером. Геттер регистрирует зависимость в Dep, сеттер уведомляет Watcher, тот ставит компонент в очередь на перерисовку.
Отсюда конкретные ограничения, а не абстрактная медленность:
- перехватываются только те свойства, которые существовали в момент создания. Добавление и удаление ключа реактивность не запускает, нужны
Vue.setиVue.delete; - присваивание по индексу
arr[0] = xи изменениеarr.lengthне отслеживаются, поэтому Vue подменяет методы массива:push,pop,shift,unshift,splice,sort,reverse; - обход выполняется сразу и целиком, включая ветки данных, которые никто не читает. На больших вложенных структурах это заметная цена на старте.
Vue 3. Объект оборачивается в Proxy, перехватываются операции get, set, has, deleteProperty. Поэтому добавление и удаление ключей, работа с индексами массива, а также Map и Set реактивны сами по себе, и Vue.set больше не нужен.
Вторая выгода Proxy в лени: вложенный объект оборачивается только тогда, когда до него добрались, поэтому инициализация дешевле. Отслеживание зависимостей переехало на уровень эффектов (effect, track, trigger) и больше не привязано к инстансу компонента, из-за чего computed и watch работают в обычных модулях, вне компонентов.
Про API: reactive() работает только с объектами, ref() заворачивает любое значение, включая примитив, в объект со свойством .value. В шаблоне .value разворачивается автоматически, в скрипте нет. Деструктуризация reactive-объекта реактивность теряет, для этого есть toRefs.
Чего стоит не приписывать реактивности: Composition API это про организацию кода, он был портирован в Vue 2.7 и системой реактивности не является. Часть прироста скорости Vue 3 дают компиляторные оптимизации (patch flags, статический хойстинг, блоки), а не только Proxy. Плата за Proxy: его нельзя полифиллить, поэтому Vue 3 не поддерживает IE11.
Где спотыкаются
Сводят разницу к формуле «во Vue 2 был defineProperty, во Vue 3 стал Proxy», не объясняя, какие именно ограничения это снимает. И приписывают весь прирост производительности реактивности, забывая про компилятор шаблонов.