Использование газа в vue — это черный ящик?

JavaScript Vue.js

открытие

Во-первых, мы все знаем, чтоthrottle(节流)а такжеdebounce(防抖)Это инструмент для оптимизации производительности.

В этой статье мы кратко представим концепции этих двух, но не будем говорить о принципах этих двух функций, а поговорим об отношениях любви-ненависти между ним и vue~, но прежде чем перейти к теме, мы должны знать некоторые из них. его введение в первую очередь.

регулирование функции(throttle) означает, что метод js запускается только один раз в определенный период времени.

дросселированиеэкономить воду смысл, точно так же, как кран с проточной водой, мы можем вручную сделать поток воды немного меньше (на определенный период времени), но он будет продолжать течь.

В случае регулирования функции функция будет выполняться каждые n секунд.Обычные сценарии:

  • Реализация функции перетаскивания элемента DOM (mousemove)
  • Поиск Lenovo (keyup)
  • Рассчитать расстояние, на которое перемещается мышь (mousemove)
  • Canvas имитирует функцию монтажной области (mousemove).
  • События mousedown/keydown для стрелялок (в единицу времени может быть выпущена только одна пуля)

Функция защиты от тряски(debounce) Запускайте код только один раз, если достаточно времени простоя.

Например, в жизни поездка на автобусе означает, что в течение определенного периода времени, если люди будут проводить карты одну за другой, чтобы сесть в автобус, водитель не будет водить машину. Водитель сядет за руль только в том случае, если никто другой не украл карту. (На самом деле, пока вы помните идею троттлинга, вы можете судить о троттлинге и антитряске методом исключения)

В случае функции Anti-Shake выполнение функции всегда будет задерживаться, что приведет к эффекту, что она не будет выполнена.Обычные сценарии:

  • Каждый раз, когда изменение размера/прокрутки запускает событие статистики
  • Проверка ввода текста (отправьте запрос AJAX для проверки после непрерывного ввода текста, просто подтвердите один раз)

vue throttle

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

первое исследование

Тогда давайте посмотрим на правильную форму. (Примечание: здесь имеется в виду дроссель, написанный непосредственно в методах, то есть дроссель найден, в области комментариев есть сомнения по этому поводу)

<input @input="throttle(download(xxx))">

...
methods: {
   download: (xxx) {
   	..
   },
   throttle: (xx) {
   }
}
...

Начал задаваться вопросом, да, это действительноthrottleКак правильно написать, почему не получается, плюс давно не писалvueЧерная магия ушла, и я пока не знаю, как это объяснить.

Поторопитесь и тайно проверьте информацию, молча введите vue debounce в гугле...

image-20210124164233425

Я нашел несколько правильных способов открыть его.

image-20210124164405309

Нашел, что это работает так, но я не мог записать это в шаблон.

эмм. Не можете найти, так что начните думать? Почему это написание не работает? Подожди, что я только что сказал? Перемотать время на 3,3 секунды назад... (Почему 3,3 секунды, ведь средняя скорость речи человека составляет 200 слов в минуту)

написание? Да так и написано, это просто шаблонный синтаксис vue, реальный браузер не такой.

Кажется, у меня есть идея! Спешите узнать, как выглядит шаблон vue после компиляции

Введите в браузереvue 模板 在线эти ключевые слова.

image-20210102131222649

Вскоре мы нашли этот адресtemplate-explorer.vuejs.org/

Вводим наш шаблон в поле ввода слева.

image-20210102131310059

Получаем вот такой разборrenderфункция.

function render() {
  with(this) {
    return _c('input', {
      on: {
        "input": function ($event) {
          throttle(download(xxx));
        }
      }
    })
  }
}

Здесь мы видим, что мы можем примерно знать, что после разбора метод мониторинга ввода был обернут слоем функций. Также нетрудно догадаться, что функция, которая окончательно разрешает реальную привязку, будет выглядеть следующим образом.

xxxx.addEventListener('input', function ($event) {
		throttle(download(xxx));
})

Если это похоже на этот дроссель, я считаю, что друзья, которые знают о дросселе, могут с первого взгляда увидеть, что этот тип дросселя совершенно неэффективен.

А как насчет того, как мы только что запросили данные?

<template>
	<input @input="click" />
</template>
<script>
...
click: _.throttle(() => {
	...
})
...
</script>
function render() {
  with(this) {
    return _c('input', {
      on: {
        "input": click
      }
    })
  }
}

Таким образом, vue напрямую передает метод связывания без какой-либо упаковки.

Так что есть только одна правда

Это действительно черная магия шаблонов vue! ! ! ! !

Передовой

Затем давайте изучим принцип анализа шаблона vue через исходный код vue, чтобы углубить наше впечатление.

Поскольку эта часть представляет собой код, связанный с компиляцией событий vue, мы можем легко найти расположение исходного кода vue (в настоящее время рассматривается версия v2.6.12).

GitHub.com/v UE JS/v UE/нет…

Мы видим, что исходный код vue содержит следующий код для генерации событий.

const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/
const fnInvokeRE = /\([^)]*?\);*$/
const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
...

const isMethodPath = simplePathRE.test(handler.value)
const isFunctionExpression = fnExpRE.test(handler.value)
const isFunctionInvocation = simplePathRE.test(handler.value.replace(fnInvokeRE, ''))

if (!handler.modifiers) {
  // 判断如果是个方法或者是函数表达式,就返回 value
  if (isMethodPath || isFunctionExpression) {
    return handler.value
  }
  /* istanbul ignore if */
  if (__WEEX__ && handler.params) {
    return genWeexHandler(handler.params, handler.value)
  }
  // 如果不满足以上的情况就会包一层方法
  return `function($event){${
    isFunctionInvocation ? `return ${handler.value}` : handler.value
  }}` // inline statement
} else {
	...
}

Так как у нашего модификатора нет(modifiers), поэтому мы прокомментировали код модификаторами, чтобы предотвратить лишнее вмешательство.

Чтобы лучше понять ситуацию, мыisMethodPathназывается方法路径, в то время какisFunctionExpressionназывается函数表达式,isFunctionInvocationназывается函数调用(Хоть это и означает по-английски, но чтобы все поняли)

Из приведенного выше кода мы можем понять, что если это событие написано таким образом, который удовлетворяетisMethodPathили удовлетворитьisFunctionExpression. Тогда наш метод записи в событии будет возвращен напрямую, иначе он будет завернут в слойfunction.

Давайте рассмотрим сценарии событий один за другим.isMethodPathМетод суждения такойconst simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/, немного долго на первый взгляд, мы анализируем анализ с помощью инструментов визуализации.

jex.im/regulex/

image-20210124174535671

Из визуализации видно, что если наш режим событий соответствует приведенному выше шаблону, он пройдет обычный тест (например,handle, handle['xx'], handle["xx"],handle[xxx], handle[0], console.log )Эти случаи не обернуты в слой функций.

Другое дело, что регулярноconst fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/.

image-20210124174916857

Проще говоря, это написать анонимную функцию,(xx) => {}илиfunciton(){}.

Все случаи, кроме двух вышеупомянутых, будут покрыты слоем методов.

Помните, что в официальном руководстве по vue, когда мы пишем синтаксис шаблона, следующие два метода эквивалентны.

1.<div @click="handler"></div>

2.<div @click="handler()"></div>

Потому что при компиляции они будут скомпилированы соответственно в следующие формы.

xxx.onclick = handle

xxx.onclick = function($event) {
	return handler();
}

Сделайте то же самое, обернув слой функций, теперь вы поняли идею? Писать в vue, как ни пиши, проблем не будет.Иногда это может быть случайная ошибка руки.Это говорит о том, что эти ситуации учитываются, так же как и еда, еда подана в рот.

В случае обертывания функцией возможны два случая.

isFunctionInvocation ? return ${handler.value} : handler.value

isFunctionInvocationТест состоит в том, чтобы удалить часть вызова функции, если вы идете, удовлетворяйте方法路径, то будет еще одинreturn.

image-20210125001734095

Нарисуем картинку для подведения итогов.

vue模板编译-事件

А как же наша ситуация?

throttle(download(xxx))

Очевидно, что мы не удовлетворяем ни путь к методу, ни выражение функции, поэтому возникает «баг», о котором мы упоминали выше, пусть нашthrottleне удалось.

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

оптимальный

Итак, сказав так много выше, нам нужно решение наилучшей практики.

<template>
	<input @click="download(xxx)" />
</template>
<script>
import {debounce} from 'lodash';
...
methods: {
  download: debounce((xxx) => {
    ...
  })
}
...
</script>

сублимация

Итак, давайте объясним еще одну проблему, внешний импорт и внутреннийmethodsразница?

<template>
	<input @click="debounce(download(xxx))" />
</template>
<script>
import {debounce} from 'lodash';
</script>

Прежде всего, написанное выше будет неправильным.

Потому что метод, написанный в нашем шаблоне, должен бытьmethodsметод в , иначе он не будет найден.

Может быть, таким образом мы пишем прямо в шаблоне, какthrottleЭта функция должна быть определена вmethods, это очень недружелюбно, потому что это будет нелогично для меня, который давно не писал (Т-Т забыл).

Так почему же это нельзя написать прямо на шаблоне, ведь это тоже связано с компиляцией vue, потому что методы в шаблоне vue будут скомпилированы в_vm.xxx,Например.

<template>
	<input @click="debounce(download(xxx))" />
</template>

Приведенный выше код шаблона будет скомпилирован следующим образом.

/* template */
var __vue_render__ = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("input", {
      on: {
        click: function($event) {
          _vm.debounce(_vm.download(_vm.xxx));
        }
      }
    })
};

Вышеуказанный - код, который действительно выполнен в браузере, поэтому мы можем видеть очень четко._vmне существует вdebounce, что такжеtemplateДоступ возможен только к методам и переменным, определенным в vue.

Предварительное преимущество

Давайте исследовать сноваvue 3.0Есть ли какие-либо изменения в этом.

Ответ - нет.

специально пошел искать@vue/compiler-sfcпрохождение теста.

const sfc = require('@vue/compiler-sfc');

const template = sfc.compileTemplate({
    filename: 'example.vue',
    source: '<input @input="throttle(download(xxx))" />',
    id: ''
});
// output
import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from "vue"

export function render(_ctx, _cache) {
  return (_openBlock(), _createBlock("input", {
    onInput: _cache[1] || (_cache[1] = $event => (_ctx.throttle(_ctx.download(_ctx.xxx))));

конец

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

Это должно обсудить JSX React, хотя это хлопотно и жестоко по отношению к нам, но мы более контролируемы в своем собственном поведении (хотя Vue также может использовать JSX, но шаблоны по-прежнему являются официально рекомендуемым методом). Я также могу понять приведенную выше производительность vue, потому что он выполняет за нас много обработки, в некоторых случаях ему нужно ввести нас$event , — это объект события, который мы часто используем, но другие помогают нам справляться с этими вещами, что также заставляет нас медленно забывать его первоначальную форму, и как только возникает проблема, это ставит нас в тупик. В JSX от нас требуется писать полный код.Таким образом, нам нужно платить дополнительный труд, чтобы написать все.Может быть, как говорится в официальной документации vue, поверхностно говорить о JSX и шаблонах vue, но в любом случае, у каждого будет разное понимание этого и разные предпочтения, поэтому я резюмирую сам.

Вы закончили учить все, си :)

благодарный

Эта статья была впервые опубликована в публичном аккаунте«Записки осеннего ветра»., добро пожаловать, чтобы следовать.