Недавно у меня было собеседование, где меня попросили создать функцию, реализующую функциональное кэширование. Это также называется запоминание, и это действительно классный способ повысить эффективность ваших функций, когда вы нажимаете на большой объем входных данных.
Функциональное кэширование — это процесс сохранения в кэше значений, записанных с момента предыдущего выполнения функции.
Итак, скажем, мы хотим создать функцию, которая складывает все целые числа под заданным целым числом, но также сохраняет значения последнего запуска в массиве, чтобы функция могла сохранить свою работу при следующем запуске? Давайте попробуем.
Основная функция, с которой мы начнем, такова:
function addAll(number){ answer = 0; for(var i = 0; i <= number; i++){ answer += i; } return answer; } addAll(5) // returns 15
Функция просто берет все целые числа ниже заданного целого числа и складывает их вместе. Не ракетостроение. Мы могли бы запустить это один раз, передав 10 000, и оно вернет 50 005 000. Прохладный. Но что, если мы хотим запустить его снова и передать 10 001? Нам нужно будет попросить функцию перезапустить 0–10 000. Давайте исправим эту проблему и оптимизируем эту функцию с помощью кеша.
Первым шагом является фактическая запись в кеш — эта переменная кеша должна сохраняться после выполнения функции, но при этом не засорять глобальное пространство имен.
Помните, что Javascript рассматривает функции как объекты со свойствами.
Если написать this.cache = []; вы действительно сможете создать этот массив как свойство объекта функции.
Мы действительно хотим повторно использовать кеш следующим образом: this.cache = this.cache || [0]; и мы даже можем использовать сокращение JS для назначения свойства и отказаться от this в назначении. кеш = этот.кеш || [0]; Нам также нужно изменить наш цикл for так, чтобы он начинался в конце массива кеша и добавлялся к кешу по мере его прохождения, и заменять ответ на последнее значение кеша.
Теперь функция выглядит так:
function addAll(number){ cache = this.cache || [0]; var answer = cache[cache.length - 1]; for(var i = cache.length; i <= number; i++){ answer += i; cache.push(answer) } return answer } addAll(6) // returns 21 addAll(5) // returns 21
Теперь мы сохраняем массив предыдущих значений, прикрепленных к значениям индекса, в массиве кеша. Каждый раз, когда вы запускаете функцию после первого раза, она запоминает последний кеш.
Однако функция перебирает только те числа, которые находятся за концом существующего кеша. Это серьезная ошибка — если кеш длиннее значения входного числа, наш цикл не запустится.
Что нам нужно добавить, так это оператор if, который говорит функции просто использовать правильный ответ из кеша, если число меньше, чем длина кеша if (answer = cache[число]; теперь функция проверит, соответствует ли ответ существует в кэше, и если это так, просто верните это значение. Если нет, он выполнит остальную часть действия, которое мы только что описали.
function addAll(number){ cache = this.cache || [0]; if (number < cache.length){ answer = cache[number]; } else { answer = cache[cache.length - 1]; for(var i = cache.length; i <= number; i++){ console.log(i) answer += i; cache.push(answer) } } return answer; } addAll(10) // returns 55 addAll(9) // returns 45
Вот как выглядит функция самокэширования. К нашей функции теперь присоединено новое свойство, называемое кешем, которое сохраняется при многократном вызове функции. Если мы запустим функцию со значением, которое уже было вычислено и сохранено в свойствах массива кеша, функция экономит работу и использует уже вычисленное значение. Если нет, он сэкономит себе как можно больше работы, использует ближайшее значение в массиве кеша и выполнит его с этой точки.
Кэширование — очень важная концепция в серверном программировании, потому что по мере увеличения объема данных, проходящих через ваше программное обеспечение, эффективность становится все более и более важной. Мне очень понравился этот пример, и я подумал, что это отличное упражнение в расширении границ концепций Javascript OOP.
Надеюсь, вам понравился этот пост, проявите немного любви и подпишитесь на обновления блога от Dip-into-the-DOM!
Первоначально опубликовано на blog.alexzitowolf.com 19 августа 2015 г.