Компоненты защиты от сотрясений и дросселирования с Keep-Alive

JavaScript
Компоненты защиты от сотрясений и дросселирования с Keep-Alive

Введение

Выявлено в предыдущей статьеkeep-aliveПринцип реализации:Тщательно раскрыть принцип keep-alive, эта статья будет моделироватьkeep-aliveЭтот принцип реализует компоненты защиты от сотрясений и дросселирования Vue.

Содержание этой статьи включает в себя:

  • Описание характеристик антивибрационного/дроссельного компонента;
  • Использование компонентов, препятствующих встряхиванию / дроссельной заслонке;
  • Реализация кода компонента защиты от сотрясения / дросселирования.

Ссылка на исходный код:throttle-debounce

Защита от тряски и дросселирования

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

debounce: Grouping a sudden burst of events (like keystrokes) into a single one.
throttle: Guaranteeing a constant flow of executions every X milliseconds.

The main difference between throttling and debouncing is that throttle guarantees the execution of the function regularly, at least every X milliseconds.

который:

  • Группировка внезапных (множественных) событий в одно событие называется防抖, например, быстро нажмите кнопку входа в систему 10 раз (вызовите 10 событий щелчка) и сгруппируйте их в одно событие щелчка с помощью операции защиты от сотрясений.
  • Убедитесь, что функция работает регулярно, выполняя функцию каждые X миллисекунд.节流, например событие прокрутки мыши, которое ограничивает выполнение события прокрутки мыши каждые 50 мс путем регулирования.

2. Характеристики антивибрационных и дросселирующих компонентов

Первый столбец следующей таблицы представляет характерный элемент,keep-aliveСтолбцы проходят черезанализ исходного кода keep-aliveвывод,Debounceа такжеThrottleСтолбцы — это эффекты функций, которые нам нужно смоделировать для достижения.

характеристика keep-alive Debounce Throttle
Объект действия Первый дочерний компонент по умолчанию Событие Click/Input по умолчанию Событие Click/Input по умолчанию
include Определить белый список компонентов кэша Определить белый список событий защиты от сотрясений Определить белый список событий регулирования
exclude Определить черный список кеша Определить черный список защиты от сотрясений Определить черный список регулирования
max Определить максимальное количество компонентов кэша / /
Динамический мониторинг Список кешей мониторинга в реальном времени Мониторинг в реальном времени списка защиты от сотрясений Список дроссельной заслонки в режиме реального времени
таймер / Определить временной интервал защиты от сотрясений Определите интервал регулирования
пользовательская функция хука / обычай перед крючком обычай перед крючком

3. Использование

  • Сначала зарегистрируйте компонент:
import Debounce from '@/components/Debounce'
import Throttle from '@/components/Throttle'

Vue.component('Debounce', Debounce)
Vue.component('Throttle', Throttle)

После регистрации им можно пользоваться по всему миру.

  • Использование по умолчанию:
<Throttle>
    <input type="text" class="common-input"
        v-model="model"
        @input="myinput" />
</Throttle>

Этот пример показывает, чтоinputэлементальinputСобытие добавляет эффект регулирования, а интервал регулирования является значением по умолчанию.300ms.

  • С параметрами
<Throttle time="500" include="keyup" exclude="input" :before="beforeHook">
    <input type="text" v-model="model" @keyup="keyUpCall" />
</Throttle>

includeа такжеexcludeиспользование параметров иkeep-aliveто же самое, может бытьString,Array,Regexpлюбой тип в ;timeобъявить интервал;beforeдля функции хука.

4. Слезный дроссель

определениеThrottleОсновные свойства компонентов

export default {
    name: 'Throttle',
    abstract: true,
    props: {
      include: [Array, String, RegExp],
      exclude: [Array, String, RegExp],
      time: [String, Number],
      before: Function
    },
    // ...
}

настраиватьabstractОпределите его как абстрактный компонент, чтобы он игнорировался при построении дерева компонентов;propsОпределяет все параметры, поддерживаемые компонентом.

определениеThrouttleкрючок компонента

export default {
    // ...
    created () {
        this.originMap = new Map // 缓存原始函数
        this.throttleMap = new Map // 缓存节流函数
        this.default = new Set // 缓存默认节流的事件类型
        this.__vnode = null // 节流组件包裹的组件实例
    },
    mounted () {
        this.$watch('include', val => { // 监听include参数变化,实时更新节流函数
            pruneThrottle(this, name => matchs(val, name))
        })
        this.$watch('exclude', val => {
            pruneThrottle(this, name => !matchs(val, name))
        })
    },
    destroyed () {
        this.originMap = new Map
        this.throttleMap = new Map
        this.default = new Set
        this.__vnode = null
    },
    // ...

createdИнициализируйте переменную кеша в хуке:originMapкешировать исходную функцию события (перед дросселированием),throttleMapфункция события после дросселирования кеша,defaultТип регулируемого события кэширования по умолчанию,__vnodeКэшировать дочерние компоненты, обернутые дроссельным компонентом;mountedпосадить на крючокincludeа такжеexcludeДва параметра события слушателя;destroyedХук уничтожает переменную.

посмотриpruneThrottleа такжеmatchs

const pruneThrottle = (vm, filter) => {
    const { throttleMap, originMap, __vnode } = vm
    Object.keys(throttleMap).filter(!filter).forEach((each) => {
        Reflect.deleteProperty(throttleMap, each)
        Reflect.set(__vnode.data.on, each, originMap[each])
    })
}

Чтобы отменить дросселирование событий, которые были дросселированы,matchsЛогика сопоставления определена внутри:

const match = (pattern, name) => {
    if(Array.isArray(pattern)) return pattern.includes(name)
    if(typeof pattern === 'string') return new Set(pattern.split(',')).has(name)
    if(isRegExp(pattern)) return pattern.test(name)
    return false
}

Поддерживает три типа сопоставления: строковое, массивное и обычное. последний взглядrenderОпределение:

export default {
    // ...
    render () {
        const vnode = this.$slots.default[0] || Object.create(null)
        this.__vnode = vnode
        // 针对不同的元素类型设置默认节流事件
        if(vnode.tag === 'input') {
            this.default.add('input')
        } else if(vnode.tag === 'button') {
            this.default.add('click')
        }
        const { include, exclude, time } = this
        const evts = Object.keys(vnode.data.on)
        const timer = parseInt(time)
        evts.forEach((each) => {
            if(
                (include && match(include, each))
                || (exclude && !match(exclude, each))
                || (!match(exclude, each) && this.default.has(each))
            ) {
                this.originMap.set(each, vnode.data.on[each]) // 缓存原始事件函数
                this.throttleMap.set(each, throttle.call(vnode, vnode.data.on[each], timer, this.before)) // 缓存节流事件函数
                vnode.data.on[each] = this.throttleMap.get(each) // 重新赋值组件实例的事件函数
            }
            })
        return vnode
    }
}

Основная логика заключается в том, чтобы сначала получить первый обернутый экземпляр подкомпонента и все определенные им типы событий;tagУстановите тип события для регулирования по умолчанию (inputэлементinputмероприятие,buttonэлементclickсобытие); затем после сопоставления правил черного и белого списка передать указанную функцию события черезthrottleДросселирование функций.

посмотри сноваthrottleОпределение:

const throttle = (func, wait, before) => {
    let isInvoking = false
    wait = wait || 300
    return (arg) => {
        if (isInvoking) return
        isInvoking = true
        before && before.call(this)
        window.setTimeout(async () => {
            if(!Array.isArray(func)) {
                func = [func]
            }
            for(let i in func) {
                await func[i].call(this, arg)
            }
            isInvoking = false
        }, wait)
    }
}

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

5. Поймай все сразу: Отказ

Эммм... На самом деле принцип реализации Debounce точно такой же, как и у Throttle, но есть некоторые отличия в коде, подробнее смотрите в коде:Demo