vue2.x сложные вопросы, на сколько вы можете ответить

внешний интерфейс Vue.js
vue2.x сложные вопросы, на сколько вы можете ответить

Есть старая поговорка, с нашими родителями мы всегда будем детьми, а с большими парнями я всегда буду цыпленком 🐣🐣🐣. Несмотря ни на что, страсть к обучению никогда не умрет. Если ответ неверный, спасибо за совет 🌚

Первый личный блог

Лучшее время посадить дерево было десять лет назад, затем сейчас

Что стоит изучить в исходном коде vue

  1. 柯里化: функция изначально имеет несколько параметров, которые передаются только一个параметры, сгенерировать новую функцию, и новая функция получает оставшиеся параметры для запуска, чтобы получить структуру
  2. 偏函数: функция изначально имеет несколько параметров, которые передаются только一部分параметры, сгенерировать новую функцию, и новая функция получает оставшиеся параметры для запуска, чтобы получить структуру
  3. 高阶函数: функция参数是一个函数, функция обрабатывает функцию параметра для получения функции, и функция, используемая для этой обработки, является функцией более высокого порядка
  4. ...

vue отзывчивая система

Краткое описание: Он будет использоваться при инициализации vue.Object.defineProperty()Добавить к каждому атрибуту в данныхgetterиsetter, при созданииdepиwatcherпровести依赖收集и派发更新, наконец черезdiffАлгоритм сравнивает разницу между новым и старым vnode черезpatchМгновенное обновление DOM

Простая схема:

Подробная версия

Вы можете обратиться к следующемуАдрес ссылки на изображение: Иллюстрация принципа отзывчивости Vue

Почему данные Vue часто меняются, но обновляются только один раз

  1. Обнаружено изменение данных
  2. открыть очередь
  3. Буферизировать все изменения данных в одном и том же цикле событий
  4. если то же самоеwatcher (watcherId相同)Запускается несколько раз, он будет помещен только в очередь一次

Без оптимизации каждое изменение данных будет выполняться:setter->Dep->Watcher->update->run

Оптимизировано:执行顺序update -> queueWatcher -> 维护观察者队列(重复id的Watcher处理) -> waiting标志位处理 -> 处理$nextTick(在为微任务或者宏任务中异步更新DOM)

Vue использует дефекты Object.defineProperty()

Свойство длины массива инициализируетсяconfigurable false, поэтому невозможно прослушивать свойство length с помощью метода get/set.

In vue путем перезаписи七个Метод, который может изменить исходный массив для мониторинга данных

Объект по-прежнему использует Object.defineProperty() для добавления get и set для прослушивания.

Ссылаться на

Принцип Vue.nextTick()

Отложенный обратный вызов выполняется после завершения следующего цикла обновления DOM. Используйте этот метод сразу после изменения данных, чтобы получить обновленную модель DOM.

Реализация исходного кода:Promise > MutationObserver > setImmediate > setTimeout

Справочная статья:Анализ принципа работы Vue.nextTick()

Принцип реализации вычисляемого

по сути, это наблюдатель с ленивой оценкойcomputed watcher. через его внутреннююthis.dirtyСвойство указывает на необходимость повторной оценки вычисляемого свойства.

  • При изменении состояния зависимости вычисляемого ленивый наблюдатель будет уведомлен,computed watcherпройти черезthis.dep.subs.lengthОпределить, есть ли подписчики,
  • Если есть, то он будет пересчитан, а затем будут сравнены новые и старые значения, и если они изменились, то будут перерендерены. (Vue хочет убедиться, что это не просто значение, от которого зависит вычисляемое свойство, но когда вычисляемое свойство изменяется最终计算的值изменяется только тогда, когда触发渲染 watcherРерендеринг — это, по сути, оптимизация. )
  • Если нет, просто поставьтеthis.dirty = true(Когда вычисляемое свойство зависит от других данных, это свойство не будет пересчитано немедленно. Оно будет вычислено только тогда, когда свойство нужно будет прочитать в другом месте позже, то есть оно имеет функцию ленивых (ленивых вычислений).)

Понимание часов

watchКеширования нет, это скорее функция наблюдения, которая может отслеживать определенные данные для выполнения обратных вызовов. когда нам нужно深度监听对象中, вы можете включить опцию deep: true, которая будет отслеживать каждый элемент в объекте. Это приведет к проблемам с производительностью.Если вы оптимизируете, вы можете использовать мониторинг строковой формы.

Примечание. Watcher: Объект наблюдателя, экземпляры делятся на渲染 watcher (render watcher),计算属性 watcher (computed watcher),侦听器 watcher(наблюдатель за пользователем) три

vue алгоритм сравнения

  • Сравните только старый и новый дочерние узлы с одним и тем же родительским узлом (сравнивается Vnode), а временная сложность составляет всего O (n)
  • При сравнении diff петля сходится с обеих сторон к середине

Процесс сравнения нового и старого узла

1. ПервыйК тому же узлу, который не нужно перемещать, поиск повторно используемого узла с помощью значения ключа является наименее затратным.

2. Найти такой же, но нужный移动узел, который потребляет второй по величине

3. В конце концов, если вы не можете найти его, вы пойдете新建删除Узел, гарантированная обработка дна

Примечание. В процессе сравнения старых и новых узлов два дерева Vnode не будут изменены.比较的结果直接对 真实DOM 进行修改

Патч Vue即时的, чтобы не упаковывать все модификации и, наконец, вместе манипулировать DOM (React ставит обновления в очередь и обрабатывает их централизованно)

Справочная статья:Подробное объяснение принципа Vue virtual dom diff

процесс рендеринга vue

  1. перечислитьcompilefunction для генерации строки функции рендеринга, процесс компиляции выглядит следующим образом:
  • parse использует большое количество регулярных выражений для анализа строки шаблона и преобразует теги, инструкции, атрибуты и т. д. в абстрактные синтаксические деревья AST.模板 -> AST (最消耗性能)
  • Оптимизация проходит через AST, находит некоторые статические узлы и помечает их, чтобы эти статические узлы можно было пропустить непосредственно при сравнении различий при повторном отображении страницы.优化runtime的性能
  • Generate преобразует окончательный AST в строку функции рендеринга.
  1. перечислитьnew WatcherФункция, отслеживающая изменения данных, когда данные изменяются, функция рендеринга выполняется для создания объектов vnode.
  2. перечислитьpatchметод, сравнивайте старые и новые объекты vnode, а также добавляйте, изменяйте и удаляйте реальные элементы DOM с помощью алгоритма DOM diff.

В сочетании с исходным кодом расскажите о жизненном цикле vue.

Официальная схема жизненного цикла Vue

Для чего используются ключи в Vue?

Ключ — это уникальный идентификатор, присвоенный каждому vnode, в зависимости от ключа наша операция сравнения может быть более точной и быстрой.

Точнее: поскольку ключ не используется повторно на месте, повторного использования на месте можно избежать в той же самой функции Node a.key === сравнение b.key. Поэтому будет точнее, если ключ не добавить, то сохранится состояние предыдущей ноды, что вызовет ряд багов.

Быстрее: ключи唯一性Он может быть полностью использован структурой данных Map.По сравнению с временной сложностью обходного поиска O (n), временная сложность Map составляет всегоO(1), исходный код выглядит следующим образом:

function createKeyToOldIdx(children, beginIdx, endIdx) {
  let i, key;
  const map = {};
  for (i = beginIdx; i <= endIdx; ++i) {
    key = children[i].key;
    if (isDef(key)) map[key] = i;
  }
  return map;
}

Примечание: в没有keyслучае, это будет быстрее. Спасибо за раздел комментариев братанfengyangyangНапоминание: Цитируя официальный сайт: специальный атрибут ключа в основном используется в алгоритме виртуального DOM Vue для идентификации VNodes при сравнении старых и новых узлов.如果不使用 key, Vue будет использовать最大限度减少动态元素и старайся как можно больше就地修改/复用Алгоритмы для элементов одного типа. При использовании ключа он изменит порядок элементов на основе изменения ключа и удалит элементы, ключ которых не существует.

Существует несколько режимов маршрутизации vue-router.

По умолчанию:"hash"(среда браузера) |"abstract"(среда Node.js)

Дополнительные значения:"hash" | "history" | "abstract"

Настройте режим маршрутизации:

  • hash: использовать хэш URL для маршрутизации.支持所有浏览器, включая браузеры, не поддерживающие HTML5 History API.
  • history: зависит отHTML5 History APIи конфигурация сервера.
  • abstract: поддерживает все среды выполнения JavaScript, такие как серверная часть Node.js. Маршруты автоматически переводятся в этот режим, если API браузера не найден.

Расскажите о принципе реализации keep-alive

определение

keep-aliveКомпонент принимает три параметра свойства:include,exclude,max

  • includeУкажите, что нужно кэшировать组件nameКоллекция, поддержка форматов параметровString, RegExp, Array。Когда это строка, несколько имен компонентов разделяются запятыми.
  • excludeУказывает, что кэширование не требуется组件nameCollection, формат параметра такой же, как и include.
  • maxУказывает максимальное количество компонентов, которые можно кэшировать, и удаляет первый компонент, если это число превышается. Формат параметра поддерживает строки и числа.

принцип

keep-aliveЭкземпляр будет кэшировать виртуальный узел соответствующего компонента.При попадании в кеш соответствующий виртуальный узел будет возвращен непосредственно из объекта кеша.

LRU(Least recently used)Алгоритм удаляет данные на основе исторических записей доступа к данным. Основная идея заключается в том, что «если доступ к данным был осуществлен недавно, вероятность доступа к ним в будущем также выше». (Закон Мерфи: чем больше вы беспокоитесь, тем больше вероятность того, что это произойдет)

Методы разрешения для доступа к свойствам объекта

например: посетите a.b.c.d

каррирование функции + замыкание + рекурсия

    function createGetValueByPath( path ) {
      let paths = path.split( '.' ); // [ xxx, yyy, zzz ]
      
      return function getValueByPath( obj ) {
        let res = obj;
        let prop;
        while( prop = paths.shift() ) {
          res = res[ prop ];
        }
        return res;
      }
    }
    
    let getValueByPath = createGetValueByPath( 'a.b.c.d' );
    
    var o = {
      a: {
        b: {
          c: {
            d: {
              e: '正确了'
            }
          }
        }
      }
    };
    var res = getValueByPath( o );
    console.log( res );

Переписать 7 методов массива в vue

Вью через原型拦截способ переписать 7 методов массива, сначала получить значение массиваObserver. Если есть новое значение, вызовитеobserveArrayПрослушайте новое значение, затем вызовитеnotify,Уведомлениеrender watcher,воплощать в жизньupdate

const arrayProto = Array.prototype;
export const arrayMethods = Object.create(arrayProto);
const methodsToPatch = [
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse"
];

methodsToPatch.forEach(function(method) {
  // cache original method
  const original = arrayProto[method];
  def(arrayMethods, method, function mutator(...args) {
    const result = original.apply(this, args);
    const ob = this.__ob__;
    let inserted;
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
    }
    if (inserted) ob.observeArray(inserted);
    // notify change
    ob.dep.notify();
    return result;
  });
});

Observer.prototype.observeArray = function observeArray(items) {
  for (var i = 0, l = items.length; i < l; i++) {
    observe(items[i]);
  }
};

vue обрабатывает реактивную реализацию defineReactive

    // 简化后的版本 
    function defineReactive( target, key, value, enumerable ) {
      // 折中处理后, this 就是 Vue 实例
      let that = this;

      // 函数内部就是一个局部作用域, 这个 value 就只在函数内使用的变量 ( 闭包 )
      if ( typeof value === 'object' && value != null && !Array.isArray( value ) ) {
        // 是非数组的引用类型
        reactify( value ); // 递归
      }

      Object.defineProperty( target, key, {
        configurable: true,
        enumerable: !!enumerable,

        get () {
          console.log( `读取 ${key} 属性` ); // 额外
          return value;
        },
        set ( newVal ) {
          console.log( `设置 ${key} 属性为: ${newVal}` ); // 额外

          value = reactify( newVal );

        }
      } );
    }

Vue отзывчивая реактивная реализация

// 将对象 o 响应式化
    function reactify( o, vm ) {
      let keys = Object.keys( o );

      for ( let i = 0; i < keys.length; i++ ) {
        let key = keys[ i ]; // 属性名
        let value = o[ key ];
        if ( Array.isArray( value ) ) {
          // 数组
          value.__proto__ = array_methods; // 数组就响应式了
          for ( let j = 0; j < value.length; j++ ) {
            reactify( value[ j ], vm ); // 递归
          }
        } else {
          // 对象或值类型
          defineReactive.call( vm, o, key, value, true );
        }
      }
    }

Почему доступ к атрибуту данных не требует данных

Доступ к недвижимости Proxy it.data.xxx в Vue для преобразования реализации этого.xxx

    /** 将 某一个对象的属性 访问 映射到 对象的某一个属性成员上 */
    function proxy( target, prop, key ) {
      Object.defineProperty( target, key, {
        enumerable: true,
        configurable: true,
        get () {
          return target[ prop ][ key ];
        },
        set ( newVal ) {
          target[ prop ][ key ] = newVal;
        }
      } );
    }

Ссылочные статьи (кроме того, где статья уже говорится)