Двусторонняя привязка данных теперь является одной из важнейших функций клиентских приложений. Без привязки данных разработчику приходится иметь дело с большим количеством логики для ручной привязки данных к представлению всякий раз, когда происходит изменение в модели. Библиотеки JavaScript, такие как Knockout , AngularJS и Ember , поддерживают двустороннее связывание, но эти библиотеки используют различные методы для обнаружения изменений.
Нокаут и Эмбер используют наблюдаемые. Наблюдаемые — это функции, обернутые вокруг свойств объектов модели. Эти функции вызываются всякий раз, когда происходит изменение значения соответствующего объекта или свойства. Хотя этот подход работает хорошо, обнаруживает и уведомляет обо всех изменениях, он лишает свободы работы с простыми объектами JavaScript, поскольку теперь нам приходится иметь дело с функциями.
Angular использует грязную проверку для обнаружения изменений. Этот подход не загрязняет модельный объект. Он регистрирует наблюдателей для каждого объекта, добавленного в модель. Все эти наблюдатели выполняются всякий раз, когда включается цикл дайджеста Angular, и если есть какие-либо изменения в данных. Эти изменения обрабатываются соответствующими наблюдателями. Модель по-прежнему остается простым объектом, так как вокруг нее не создаются обертки. Но этот метод вызывает снижение производительности по мере роста числа наблюдателей.
Что такое Object.observe
Object.observe
O.o
Хотя ES7 еще не завершена, эта функция уже поддерживается в браузерах на основе Blink (Chrome и Opera).
Поскольку Object.observe
Если Object.observe
Это не означает, что все существующие библиотеки двустороннего связывания будут бесполезны после реализации O.o
Нам все еще нужно, чтобы они эффективно обновляли пользовательский интерфейс после обнаружения изменений с помощью O.o
Кроме того, библиотеки внутренне заполняют логику обнаружения изменений, если не все целевые браузеры поддерживают O.o
Наблюдение за свойствами объекта
Теперь, когда у вас есть представление о том, для чего O.o
Метод observe()
Object
Может использоваться для поиска изменений объекта и принимает три параметра:
- объект для наблюдения
- функция обратного вызова, которая вызывается при обнаружении изменения
- необязательный массив, содержащий типы изменений для отслеживания
Давайте посмотрим пример использования метода. Рассмотрим следующий фрагмент:
var person = {
name: 'Ravi',
country: 'India',
gender: 'Male'
};
function observeCallback(changes){
console.log(changes);
};
Object.observe(person, observeCallback);
person.name = 'Rama'; // Updating value
person.occupation = 'writer'; // Adding a new property
delete person.gender; // Deleting a property
В этом коде мы создали объектный литерал с некоторыми данными. Мы также определили функцию с именем observeCallback()
Затем мы начинаем наблюдать за изменениями, используя O.o
Наконец, мы выполнили некоторые изменения на объекте.
Если вы увидите вывод на консоли, вы увидите, что все три изменения обнаружены и зарегистрированы. На следующем снимке экрана показан результат, полученный фрагментом кода:
O.o
Итак, здесь мы получили три записи для трех изменений, примененных к объекту. Как видите, каждая запись состоит из имени измененного свойства, старого значения, типа изменения и самого объекта с новыми значениями.
Ниже приведена живая демонстрация предыдущего кода (не забудьте открыть консоль, чтобы увидеть результат):
В нашем коде мы не указали типы изменений для поиска, поэтому он отслеживает добавления, обновления и удаления. Это можно контролировать с помощью третьего параметра метода observe
Object.observe(person, observeCallback, ['add', 'update']);
Регистрация уведомлений
Метод observe()
Он не может обнаружить изменения свойств, созданных с использованием методов получения и установки. Поскольку поведение этих свойств контролируется автором, обнаружение изменений также должно принадлежать автору. Чтобы решить эту проблему, нам нужно использовать средство уведомления (доступно через Object.getNotifier()
Рассмотрим следующий фрагмент:
function TodoType() {
this.item = '';
this.maxTime = '';
var blocked = false;
Object.defineProperty(this, 'blocked', {
get:function(){
return blocked;
},
set: function(value){
Object.getNotifier(this).notify({
type: 'update',
name: 'blocked',
oldValue: blocked
});
blocked = value;
}
});
}
var todo = new TodoType();
todo.item = 'Get milk';
todo.maxTime = '1PM';
console.log(todo.blocked);
Object.observe(todo, function(changes){
console.log(changes);
}, ['add', 'update']);
todo.item = 'Go to office';
todo.blocked = true;
TodoType
В дополнение к ним добавляется blocked
Object.defineProperty
В нашем примере сеттер, определенный для этого свойства, является простым. В типичном бизнес-приложении он может выполнять некоторые проверки и может не устанавливать значение в случае сбоя проверки. Однако я хотел, чтобы все было просто.
В качестве последнего замечания вы можете видеть, что в нашем примере уведомление отправляется только при наличии обновления.
Изменение в blocked
Ниже приведена живая демонстрация этого примера (не забудьте открыть консоль, чтобы увидеть результат):
Наблюдение за множественными изменениями
Иногда мы можем выполнить вычисление после того, как два или более свойства каким-либо образом изменены. Хотя мы можем уведомить оба этих изменения по отдельности с помощью уведомителя, было бы лучше отправить одно уведомление с именем пользовательского типа, чтобы указать, что оба значения изменены. Это можно сделать с помощью метода notifier.performChange()
Этот метод принимает три аргумента:
- Название пользовательского типа
- Функция обратного вызова, выполняющая изменения. Значение, возвращаемое из этой функции, используется в объекте изменения
- Объект, к которому применяются изменения
Давайте добавим новое свойство с именем done
TodoType
Значение этого свойства указывает, завершен ли элемент задачи или нет. Когда значение done
true
blocked
true
Следующий фрагмент определяет это свойство:
var done = false;
Object.defineProperty(this, 'done', {
get: function(){
return done;
},
set: function(value){
if(value){
var notifier = Object.getNotifier(this);
if(blocked && value) {
notifier.performChange('doneAndUnblocked', function(){
done = value;
blocked = false;
return { oldDone: false, oldBlocked: true };
}, this);
}
else{
notifier.notify({
type: 'update',
name: 'done',
oldValue: done
});
done = value;
}
}
}
});
Как только логика внутри функции обратного вызова performChange
Этот тип не наблюдается Object.observe
нам нужно явно попросить O.o
В следующем фрагменте показан измененный O.o
todo
Object.observe(todo, function(changes){
console.log(changes);
}, ['add', 'update', 'doneAndUnblocked']);
todo.blocked = true;
todo.done = true;
Приведенный выше фрагмент устанавливает значение заблокированного на true
done
true
Таким образом, он отправляет уведомление с пользовательским типом изменения. На следующем снимке экрана показаны детали объекта изменения, возвращаемого пользовательским типом:
Ниже приведена живая демонстрация этого примера (не забудьте открыть консоль, чтобы увидеть результат):
Наблюдение массивов
Наблюдение за массивами аналогично наблюдению за объектами. Единственное отличие состоит в том, что функция наблюдателя должна быть зарегистрирована с использованием Array.observe
Object.observe
Следующий фрагмент демонстрирует это:
var array = ['morning', 'Afternoon', 'Evening'];
var arrayObserver = function(changes){
console.log(changes);
};
Array.observe(array, arrayObserver);
array[0] = 'Morning';
array.push('Night');
array.splice(1, 1);
Ниже приведена живая демонстрация этого примера (не забудьте открыть консоль, чтобы увидеть результат):
Удаление зарегистрированных наблюдателей
Зарегистрированный наблюдатель на объекте или массиве может быть удален с помощью Object.unobserve()
Array.unobserve()
Этот метод принимает два параметра: объект или массив и обратный вызов для удаления. Итак, чтобы использовать этот метод, нам нужно иметь ссылку на обратный вызов.
Object.unobserve(person, observeCallback);
Вывод
Как только O.o
Aurelia уже начала использовать его, библиотека обнаружения изменений Angular 2 , watchtower.js , использует O.o
Ember также собирается использовать ее для обнаружения изменений в будущем. В Angular 2 и Aurelia реализованы функции восстановления поллиний, когда O.o
Будущее вокруг двусторонней привязки на стороне клиента будет ярче с этим замечательным дополнением к браузерам. Давайте с нетерпением ждем других браузеров, чтобы наверстать упущенное раньше!