02.01.2018

Pure computed переменные — Knockout.js


Pure computed (чисто вычисляемые) переменные, введенные в Knockout 3.2.0, предоставляют более оптимизированный с точки зрения производительности и использования памяти вариант computed-переменных для большинства приложений в сравнении с обычными computed-переменными. А все потому, что pure computed переменные не поддерживают подписки на их зависимости, когда на них самих нет подписок. Это предоставляет:

  • Предотвращение утечки памяти от computed-переменных, на которые более нет ссылок в приложении, но чьи зависимости все ещё существуют.
  • Уменьшает расход ресурсов на вычисления не пересчитывая computed-переменные, чьи значения не наблюдались в других местах.

Pure computed-переменные автоматически переключаются между двумя состояниями на основе того, есть ли у них подписчики на событие change (изменение значения) или нет.

  1. Когда нет подписчиков на событие change, она находится в режиме сна (sleeping). При переходе в режим сна, она распоряжается всеми подписками на её зависимости. Во время этого состояния, она не подписывается ни на какие observables-переменные, к которым получала доступ внутри тела своей функции (хотя и отслеживает их изменения). Если значение computed-переменной было прочитано, когда она находится в состоянии сна, то она автоматически пересчитывается если любая из её зависимостей изменилась.
  2. Когда имеет любые подписчики на событие change, то она бодрствует и слушает (listening). При переходе в состояние слушаю, она незамедлительно подписывается на все зависимости. В этом состоянии, она работает как обычная computed observable, как описано в главе «как работает отслеживание зависимостей«.

Почему “pure”?

Мы позаимствовали этот термин из чистых функций потому что эта возможность в целом применима только к computed-переменным, чьи функции расчета являются чистыми функциями по следующим пунктам:

  1. Расчет computed-переменной не должен вызывать побочных (посторонних) эффектов.
  2. Значение 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

Перепечатка и копирование строго запрещены.

Оригинал страницы

Опубликовано: 02/01/2018

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *