Вы когда-нибудь задумывались, как поиск Google может предлагать поисковые предложения, когда вы вводите текст в строке поиска? Давайте задумаемся об этом на мгновение. Прежде всего, какую функциональность мы наблюдаем? Что ж, для каждой буквы, которую пользователь вводит в строку поиска, создается список предлагаемых запросов, который отображается под строкой поиска. Это означает, что в терминах React для каждого изменения символа должна быть функция обратного вызова, которая проверяет список возможных поисков и возвращает совпадение. Откуда список? Я могу предположить два сценария. Во-первых, он отправляется в тот момент, когда пользователь входит на страницу поиска Google. Во-вторых, сетевой запрос отправляется каждый раз, когда пользователь что-то вводит. Преимущество первого метода заключается в том, что мы уменьшим количество сетевых запросов к API, потому что после прибытия на сайт потребуется только один запрос. Недостатком является то, что мы, скорее всего, отправляем довольно много данных, большая часть которых не будет использоваться, что неэффективно (подумайте, сколько существует возможных поисковых запросов по сравнению с тем, который вы вводите, это много потерянных данных). Второй сценарий был бы более целенаправленным и, следовательно, более эффективным с точки зрения данных (мы отправляем обратно только данные сопоставленного списка), но привел бы к огромному объему запросов предложений API. О каком объеме мы говорим? Согласно этой статье, в Google совершается более 40–60 миллиардов поисков в месяц. Давайте просто возьмем число в 60 миллиардов, что соответствует примерно 2 миллиардам поисковых запросов в день или примерно 1,4 миллиона поисковых запросов в минуту. Согласно той же статье, указанной выше, самый распространенный поисковый запрос имеет длину 2 слова. Для простоты предположим, что среднее английское слово состоит из 5 букв. Таким образом, в среднем запросы Google состоят из 11 символов (включая пробел). Это означает, что API, который обслуживает предложения запросов, обрабатывает примерно 250 тыс. запросов API в секунду. Теперь у них, скорее всего, есть несколько серверов по всему миру, оптимизированных для этого. Тем не менее, это тонна запросов на обслуживание!

Так какой сценарий они реализуют? Давайте разберемся. Мы можем перейти на Google.com, открыть инструменты разработчика и просмотреть сетевые запросы. Немного поэкспериментировав, я обнаружил, что (за некоторыми исключениями) для каждого изменения буквы отправляется сетевой запрос, поэтому у них есть своего рода выделенная конечная точка API для обслуживания предложений запросов.

Давайте представим, что мы Google и хотим реализовать функциональность в React. Вот компонент React, который обеспечивает желаемую функциональность:

Здесь у нас есть компонент на основе класса, который отображает контролируемую форму, содержащую метку и ввод. К входным данным подключен прослушиватель событий onChange, который вызывает функцию обратного вызова handleChange. Ниже формы мы просто перебираем список предложений (инициализированный как пустой массив) и перечисляем каждый элемент предложения в div (причудливо, я знаю). В функции обратного вызова handleChange мы обновляем состояние запроса и отправляем запрос на выборку, чтобы получить предложения. В случае API предложений Google, у них, вероятно, есть несколько серверов. Таким образом, чтобы защитить себя от последствий отправки запросов на выборку на разностные серверы, мы обновляем предложения только в том случае, если текущее значение нашего ввода соответствует нашему состоянию. Если у нас не было этой проверки и мы отправляем запросы на выборку на разные серверы, более медленный из двух серверов может привести к тому, что мы установим состояние после того, как мы уже перешли к другому слову, поскольку для каждого запроса на выборку должно выполняться обещание .then. выполнять.

Хорошо, теперь давайте предположим, что мы не Google и у нас нет безумно мощного API предложений для обслуживания каждого нашего запроса. Предположим, у нас есть API предложений, но нам нужно уменьшить количество запросов API, поступающих для каждого пользователя. Для этого нам нужна какая-то задержка в нашем запросе на выборку, то есть мы не будем отправлять запрос на выборку, пока не пройдет определенное время. Это функция устранения дребезга. Итак, давайте рефакторинг.

К счастью для нас, lodash уже создал для нас функцию устранения дребезга. Код практически тот же, но теперь мы говорим, что метод handleChange не должен выполняться, если между вызовами не прошло 500 мс. Теперь, если пользователь очень быстро набирает кучу бессмысленных символов, мы не будем тратить драгоценную пропускную способность API.

Теперь, когда мы зашли так глубоко, давайте продолжим. Нам следует иметь дело со случаем, когда мы размонтируем наш компонент до выполнения метода handleChange. Если мы этого не сделаем, наша программа рухнет, потому что мы пытаемся установить состояние для размонтированного компонента. Чтобы справиться с этим случаем, lodash предоставляет нам метод отмены. Итак, все, что нам нужно сделать, это использовать метод жизненного цикла componentWillUnmount и вызвать метод отмены в нашем методе handleChange.

Не так уж и плохо? Итак, теперь у нас есть функция handleChange с ограничением скорости (отказ от отказов), которая по-прежнему будет динамически обновлять наши предложения по мере ввода с возможностью ограничения скорости, насколько нам нужно, чтобы ограничить снижение производительности нашего API предложений.

Я благодарю г-на Мэтью Даля, старшего разработчика интерфейса, за то, что он вдохновил меня написать это.

Ваше здоровье.