Pure computed переменные — Knockout.js
Pure computed (чисто вычисляемые) переменные, введенные в Knockout 3.2.0, предоставляют более оптимизированный с точки зрения производительности и использования памяти вариант computed-переменных для большинства приложений в сравнении с обычными computed-переменными. А все потому, что pure computed переменные не поддерживают подписки на их зависимости, когда на них самих нет подписок. Это предоставляет:
- Предотвращение утечки памяти от computed-переменных, на которые более нет ссылок в приложении, но чьи зависимости все ещё существуют.
- Уменьшает расход ресурсов на вычисления не пересчитывая computed-переменные, чьи значения не наблюдались в других местах.
Pure computed-переменные автоматически переключаются между двумя состояниями на основе того, есть ли у них подписчики на событие change (изменение значения) или нет.
- Когда нет подписчиков на событие change, она находится в режиме сна (sleeping). При переходе в режим сна, она распоряжается всеми подписками на её зависимости. Во время этого состояния, она не подписывается ни на какие observables-переменные, к которым получала доступ внутри тела своей функции (хотя и отслеживает их изменения). Если значение computed-переменной было прочитано, когда она находится в состоянии сна, то она автоматически пересчитывается если любая из её зависимостей изменилась.
- Когда имеет любые подписчики на событие change, то она бодрствует и слушает (listening). При переходе в состояние слушаю, она незамедлительно подписывается на все зависимости. В этом состоянии, она работает как обычная computed observable, как описано в главе «как работает отслеживание зависимостей«.
Почему “pure”?
Мы позаимствовали этот термин из чистых функций потому что эта возможность в целом применима только к computed-переменным, чьи функции расчета являются чистыми функциями по следующим пунктам:
- Расчет computed-переменной не должен вызывать побочных (посторонних) эффектов.
- Значение computed-переменной не должно изменяться на основе количества расчетов другой “скрытой” информации. Её значение должно быть основано на вычислении значений других observable-переменных приложения, которые, в рамках определения чистой функции, рассматриваются как её параметры.
Синтаксис
Стандартным методом определения pure computed-переменной является использование ko.pureComputed:
this.fullName = ko.pureComputed(function() {
return this.firstName() + " " + this.lastName();
}, this);
Альтернативным вариантом будет использование опции pure с обычной ko.computed:
this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this, { pure: true });
Для описания полного синтаксиса, смотри справка по computed-переменным.
Когда использовать pure computed переменные
Вы можете использовать возможность pure для любых computed-переменных, которые следуют рекомендациям по чистым функциям. Хотя, большую часть выгоды вы увидите, когда это будет применяться к интерфейсу приложения, который включает постоянные модели представления (view models), которые совместно используются и делятся с временными компонентами представления (views) и моделями представления (view models). Использование pure computed-переменных в постоянной модели представления даст прирост в производительности при вычислениях. Использование их во временных моделях представления предоставляет выгоду относительно управления памятью.
В следующем примере простого интерфейса настройки, свойство fullName является pure computed-переменной и привязано лишь к представлению во время конечного шага, и таким образом, обновляется лишь тогда, когда этот шаг активен.
See the Pen Knockout Пример 1: Pure computed by Kirill (@skv1991) on CodePen.
Исходный код: Представление
<div class="log" data-bind="text: computedLog"></div>
<!--ko if: step() == 0-->
<p>Имя: <input data-bind="textInput: firstName" /></p>
<!--/ko-->
<!--ko if: step() == 1-->
<p>Фамилия: <input data-bind="textInput: lastName" /></p>
<!--/ko-->
<!--ko if: step() == 2-->
<div>Префикс: <select data-bind="value: prefix, options: ['Мистер', 'Мисс','Миссис','Доктор']"></select></div>
<h2>Привет, <span data-bind="text: fullName"> </span>!</h2>
<!--/ko-->
<p><button type="button" data-bind="click: next">Далее</button></p>
Исходный код: Модель представления
function AppData() {
this.firstName = ko.observable('Джон');
this.lastName = ko.observable('Бёрнс');
this.prefix = ko.observable('Доктор');
this.computedLog = ko.observable('Лог: ');
this.fullName = ko.pureComputed(function () {
var value = this.prefix() + " " + this.firstName() + " " + this.lastName();
// Обычно, стоит избегать записи observable-переменных внутри pure computed
// переменной (предотвращение сторонних эффектов). Но этот пример демонстрирует
// её внутреннюю работы, и запись лога в данном случае хорошо подходит.
this.computedLog(this.computedLog.peek() + value + '; ');
return value;
}, this);
this.step = ko.observable(0);
this.next = function () {
this.step(this.step() === 2 ? 0 : this.step()+1);
};
};
ko.applyBindings(new AppData());
Когда не использовать pure computed переменные
Сторонние эффекты
Не следует использовать возможность pure для computed-переменных, которые должны выполнять действия, когда их зависимость изменилась. Пример включает:
- Использование computed-переменной для запуска callback-функции на основе множества observable-переменных.
ko.computed(function () { var cleanData = ko.toJS(this); myDataClient.update(cleanData); }, this);
- В init функции биндингов, используя computed-переменную для обновления связанного элемента.
ko.computed({ read: function () { element.title = ko.unwrap(valueAccessor()); }, disposeWhenNodeIsRemoved: element });
Причина, по которой не следует использовать pure computed, если её функция имеет важные сторонние эффекты заключается в том, что её функция не будет запущена, если у computed-переменной нет активных подписчиков (и она поэтому находится в режиме сна). Если для функции расчета важно всегда выполнять перерасчет при изменении зависимостей, используйте вместо этого обычную computed-переменную.
Определяем является ли свойство pure computed переменной
В некоторых сценариях, бывает удобно программно определять, является ли интересующая переменная pure computed-переменной. Knockout предоставляет вспомогательную функцию, ko.isPureComputed чтобы помочь в данном вопросе. Например, скажем вы хотите исключить переменные, которые не pure computed из данных, которые отправляете на сервер.
var result = {};
ko.utils.objectForEach(myObject, function (name, value) {
if (!ko.isComputed(value) || ko.isPureComputed(value)) {
result[name] = value;
}
});
Уведомления об изменении состояния
Pure computed-переменные уведомляют событие awake (используя текущее значение), когда переменная переходит в состояние слушаю и уведомляет событие asleep (используя значение undefined), когда переменная входит в режим сна. Обычно вам не нужно знать о внутреннем состоянии computed-переменных. Но поскольку внутреннее состояние может соответствовать тому, привязана ли computed-переменная к представлению или нет, то можете использовать эту информацию для каких-то манипуляций по инициализации или очистке модели представления.
this.someComputedThatWillBeBound = ko.pureComputed(function () {
...
}, this);
this.someComputedThatWillBeBound.subscribe(function () {
// делаем что-то, когда переменная привязана к элементу(ам)
}, this, "awake");
this.someComputedThatWillBeBound.subscribe(function () {
// делаем что-то, когда переменная отвязана от элемента(ов)
}, this, "asleep");
(Событие awake так же применимо к обычным computed-переменным, созданным с опцией deferEvaluation.)
Эксклюзивно для сайта skv1991.ru
Перепечатка и копирование строго запрещены.