Skip to content

Latest commit

 

History

History

8.decorators

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Домашнее задание к лекции 8 «Декораторы»

Задача 1. Усовершенствовать кеширующий декоратор

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

Чтобы тесты выполнялись, функция должна возвращать следующие строки(!) «Вычисляем: 10» для первого вызова (10 для примера) и «Из кеша: 10» — для повторного. Подробнее смотрите в файле tests.js.

Для вычисления хеша нужно использовать алгоритм хеширования MD5. Для его применения в файл с тестами была подключена библиотека js-md5. То есть алгоритм MD5 применим в любой области видимости файлов скриптов, подключенных к странице с тестами.

const hasingText = "какой-нибудь текст";
console.log(md5(hasingText)); // 8d1d3ecc455a4220590e6d27e6c1a267
console.log(md5([10, 20, 30])); // 7f49b84d0bbc38e96493718013baace6

Рекомендуем параллельно выводить результаты в консоль, чтобы вам было удобнее отлаживать.

console.log("Вычисляем: " + result);
return "Вычисляем: " + result;
Подсказка 1. Хеш (однозначное соответствие «аргументы => строка») удобно реализовать через `hash = md5(args)`.

Кеш можно сделать массивом объектов. Например:

cache = [
  { hash: "7f49b84d0bbc38e96493718013baace6", value: 60 },
  { hash: "36d9d8df7a0a21c339bf74e2a30d68bd", value: 6 },
  { hash: "fd526d0a3bfd3ebdc1fc0f998d241da6", value: 791 },
];
Подсказка 2.

Тогда при каждом запуске (внутри wrapper) вам следует проверять, есть ли hash для данных аргументов в кеше.

Это можно сделать методом find. const objectInCache = cache.find((item) => тут нужно подумать)

Подсказка 3. Если элемента в кеше нет (!objectInCache), проще всего добавить новый объект в кеш и, если объектов стало больше, чем 5, удалить первый с начала.

Это можно сделать методом shift() массива.

Подсказка 4. Этот код мог бы служить базой для решения, но всё равно остаётся место для раздумий:
function cachingDecoratorNew(func) {
let cache = [];

function wrapper(...args) {
    const hash = ???; // получаем правильный хеш c помощью функции md5
    let objectInCache = cache.find((item) => ???); // ищем элемент, хеш которого равен нашему хешу
    if (objectInCache) { // если элемент найден
        console.log("Из кеша: " + ???); // индекс нам известен, по индексу в массиве лежит объект, как получить нужное значение?
        return "Из кеша: " + ???;
    }

    let result = func(...args); // в кеше результата нет — придётся считать
    cache.push(???) ; // добавляем элемент с правильной структурой
    if (cache.length > 5) { 
      ??? // если слишком много элементов в кеше, надо удалить самый старый (первый) 
    }
    console.log("Вычисляем: " + result);
    return "Вычисляем: " + result;  
}
return wrapper;
}

Какой результат мы хотели бы получить

const addAndMultiply = (a, b, c) => (a + b) * c;
const upgraded = cachingDecoratorNew(addAndMultiply);
upgraded(1, 2, 3); // вычисляем: 9
upgraded(1, 2, 3); // из кеша: 9
upgraded(2, 2, 3); // вычисляем: 12
upgraded(3, 2, 3); // вычисляем: 15
upgraded(4, 2, 3); // вычисляем: 18
upgraded(5, 2, 3); // вычисляем: 21
upgraded(6, 2, 3); // вычисляем: 24 (при этом кеш для 1, 2, 3 уничтожается)
upgraded(1, 2, 3); // вычисляем: 9  (снова вычисляем, кеша нет)

Задача 2. Декоратор debounce с моментальным вызовом и подсчётом количества вызовов

Усовершенствуйте рассмотренный на лекции debounce декоратор, добавив три дополнительные фичи:

  1. Первый вызов происходил моментально, а следующий не раньше, чем через интервал времени, причём интервал должен задаваться в момент применения декоратора к функции. Дополнительная статья про debouncing и throttling.
  2. Усовершенствуйте декоратор так, чтобы в свойстве count декорированной функции хранилось количество её вызовов. Для решения используйте подход, который был применён в лекции для декоратора-шпиона.
  3. Усовершенствуйте декоратор так, чтобы в свойстве allCount декорированной функции хранилось количество вызовов декоратора. Для решения используйте подход, который был применён в лекции для декоратора-шпиона.

графическое представление

Подсказка 1. Для ориентира при первом запуске можно опираться на идентификатор тайм-аута. При первом вызове в идентификаторе ничего не будет.
Подсказка 2. Добавьте к обёртке wrapper новое свойства `count` и `allCount`, в котором храните количество вызовов переданной функции и результата декоратора соответственно.
const sendSignal = (signalOrder, delay) => console.log("Сигнал отправлен", signalOrder, delay);
const upgradedSendSignal = debounceDecoratorNew(sendSignal, 2000);
setTimeout(() => upgradedSendSignal(1, 0)); // Сигнал отправлен + будет запланирован асинхронный запуск, который будет проигнорирован, так как следующий сигнал отменит предыдущий (300 - 0 < 2000)
setTimeout(() => upgradedSendSignal(2, 300), 300); // проигнорировано, так как следующий сигнал отменит предыдущий (900 - 300 < 2000)
setTimeout(() => upgradedSendSignal(3, 900), 900); // проигнорировано, так как следующий сигнал отменит предыдущий (1200 - 900 < 2000)
setTimeout(() => upgradedSendSignal(4, 1200), 1200); // проигнорировано, так как следующий сигнал отменит предыдущий (2300 - 1200 < 2000)
setTimeout(() => upgradedSendSignal(5, 2300), 2300); // Сигнал отправлен, так как следующий вызов не успеет отменить текущий: 4400-2300=2100 (2100 > 2000)
setTimeout(() => upgradedSendSignal(6, 4400), 4400); // проигнорировано, так как следующий сигнал отменит предыдущий (4500 - 4400 < 2000)
setTimeout(() => upgradedSendSignal(7, 4500), 4500); // Сигнал будет отправлен, так как последний вызов debounce декоратора (спустя 4500 + 2000 = 6500) 6,5с
setTimeout(() => {
  console.log(upgradedSendSignal.count); // было выполнено 3 отправки сигнала
  console.log(upgradedSendSignal.allCount); // было выполнено 6 вызовов декорированной функции
}, 7000)

Результат при правильном решении задания

графическое представление

Требования к выполнению домашней работы

  1. Все тесты успешно выполняются.
  2. Соблюдается кодстайл.
  3. Решение загружено в форкнутый репозиторий GitHub.
  4. Решение опубликовано в GitHub Pages.

Решение задач

  1. Откройте файл task.js в вашем редакторе кода и выполните задание.
  2. Проверьте соблюдение кодстайла. Форматируйте ваш код через форматтер https://codebeautify.org/jsviewer.
  3. Добавьте файл task.js в индекс git с помощью команды git add %file-path%, где %file-path% — путь до целевого файла git add ./8.decorators/task.js.
  4. Сделайте коммит, используя команду git commit -m '%comment%', где %comment% — это произвольный комментарий к вашему коммиту git commit -m 'Восьмое задание полностью готово'.
  5. Опубликуйте код в репозиторий homeworks с помощью команды git push -u origin main.
  6. На проверку пришлите 2 ссылки. На файл с решением (task.js) и на страницу GitHub Pages — страницу с автотестами: https://%USERNAME%.github.io/bjs-2-homeworks/8.decorators.

Никакие файлы прикреплять не нужно.

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

Любые вопросы по решению задач задавайте в чате учебной группы.