Комментарии 41
Кэширование — более общий термин, потому что кэшировать можно любые данные, а мемоизировать — только неизменяемые.
Побочные действия тоже замечательно мемоизируются в случае реактивного программирования.
Разделяйте функции, делающие что-то, и функции, возвращающие что надо делать :) Это хороший подход даже без нацела на мемоизацию.
Подавляющее большинство функций во фронтэнде должны что-то делать, а не возвращать какой-то результат.
Не зовите функциями процедуры
А если к мемоизации добавить трекинг зависимостей и автоматическую очистку кеша, то получится реактивное программирование :-)
подобные оптимизации — пережиток далекого прошлого
более того, подобная «оптимизация» может даже замедлить код
Вы просили реальные примеры, правда они больше подходят под слово кеширование. Был не очень адекватный клиент, который выгружал себе на страницу 50000 записей, и начинал сортировку по дате. Разумеется жаловался на то, что как-то медленно все работает. Компаратор по датам у нас был реализован относительно просто, но не оптимально. Что мы сделали: даты (как строки) преобразовывали в числа и сравнивали числа между собой, чтобы не делать постоянное преобразование из строки в число мы сделали кеш значений строка->число. Также использовали тот факт, что даты(без времени) имеют ограниченный набор реальных значений: сегодня, вчера, позавчера, максимум пол года назад, т.е кеш строк был примерно размером не более 365 записей всего. Увеличили скорость сортировки в 16 раз
Во-первых, с redux довольно успешно конкурирует mobx, где иммутабельности нет и не предвидится.
Во-вторых, с чего вы взяли, что мемоизация плохо сочетается с иммутабельностью?
Если вы работаете с React/Redux, можете взглянуть на reselect. Тут используется селектор с мемоизацией.
Без реселекта у вас более-менее сложное приложение будет тупить.
Мемоизация — это "вечное" кеширование неизменяемых данных. Такой кеш не нуждается в инвалидации.
По сути мемоизации кэш при ней всегда валиден. Не может вдруг измениться результат fact(100500) так, чтобы предыдущий результат стал не валиден.
Считать ли валидным кеш, который никому не нужен? Под инвалидацией подразумевают обычно очистку. Как в следствии его протухания (обычно никому не нужен протухший кеш), так и собственно ввиду бессмысленности его существования для дальнейшей работы.
А почему он стал невалидным вдруг? Он просто стал ненужным, значит нужно очистить.
А если вдруг функция для тех же аргументов стала отдавать другой результат — то это уже инвалидация нужна.
Вы как бы и отсутствие значения (не завершился запрос) считаете за исключительную ситуацию, что уж тут.
Всё зависит от критериев валидности, которые (внезапно!) могут быть разными и в том числе такими: "кеш считается валидным, если есть вероятность его дальнейшего полезного применения".
Для синхронного кода ожидающего результат ситуация действительно исключительная. Это не моя прихоть, а данность.
"кеш считается валидным, если есть вероятность его дальнейшего полезного применения".
У вас достаточно странное мышление. Мне, все же, как-то привычней разделять понятия валидности и необходимости.
Для синхронного кода ожидающего результат ситуация действительно исключительная
Тоже не соглашусь. Исключительная ситуация — это когда бэк пятисотит или что-то вроде. А то, что данных нет — это часть состояния, которое должно быть корректно обработано. Более того, мне очень по душе подход с использованием ADT, когда "нет данных" — это тоже данные, но с другим типом. Более того, можно даже исключительных ситуаций для потребляющего кода избежать, используя любой аналог Either.
По вашему рассматривать отсутствие данных как исключительную ситуацию (заметьте, не ошибку) — это странное мышление, а рассматривать ошибку как данные — нет?
Ну, у меня как-то в голове уложено, что эксепшены, исключительные ситуации — это ситуации, необработанные программистом, на то они, блин, и исключительные. Видимо, поэтому я обхожусь без них.
Отсутствие данных — это тоже данные, вы же отображаете где-то спиннер. Значит это часть вашего стейта.
Ошибка, ну например 404, это значит данные не найдены, надо опять что-то в интерфейсе показать. Значит это часть вашего стейта.
Даже 500, великий и ужасный, тоже требует какой-то реакции интерфейса. Значит это… ну вы поняли.
Я хочу сказать, что имею в виду следующий подход:
Раз, два, три.
Такой подход великолепно сочетается с FRP (про ORP не скажу). Мы правда на Rx сидим, но, думаю, в $mol тоже зайдет. Не пробовали?
Для FRP нужно много разных костылей. Для ОРП они просто не нужны — вы пишете простой и ясный код, предполагающий, что данные у вас есть. Именно в этом прелесть исключений — вы пишете позитивную логику, а всякие исключительные ситуации (произошла ошибка, нужно подождать и тп) прерывают позитивную логику, передавая управление сразу в общий обработчик таких ситуаций. Именно поэтому в $mol проблемы "забыл проверить флаг loading" не стоит в принципе — типовую обработку ошибок и ожиданий берёт на себя рендерер, чего хватает в подавляющем большинстве случаев. А когда нужна кастомизация обработки исключительных ситуаций — есть try-catch.
Вы немного ошибаетесь. Необработанные ситуации как правило называются ошибками (Error) или отказами (Fault). А исключения — это ситуации, требующие особой обработки.
const fibonachi = int => int <= 1 ? 1 : fibonachi(int-1) + fibonachi(int-2);
fibonachi(80) повесит браузер или интерпретатор. Нужен метод способный сохранять/проверять результаты рекурсивного вызова а не только конечный результат.
Мемоизация в JS и ускорение функций