Статьи

Введение в Object.observe

Двусторонняя привязка данных теперь является одной из важнейших функций клиентских приложений. Без привязки данных разработчику приходится иметь дело с большим количеством логики для ручной привязки данных к представлению всякий раз, когда происходит изменение в модели. Библиотеки JavaScript, такие как Knockout , AngularJS и Ember , поддерживают двустороннее связывание, но эти библиотеки используют различные методы для обнаружения изменений.

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

Angular использует грязную проверку для обнаружения изменений. Этот подход не загрязняет модельный объект. Он регистрирует наблюдателей для каждого объекта, добавленного в модель. Все эти наблюдатели выполняются всякий раз, когда включается цикл дайджеста Angular, и если есть какие-либо изменения в данных. Эти изменения обрабатываются соответствующими наблюдателями. Модель по-прежнему остается простым объектом, так как вокруг нее не создаются обертки. Но этот метод вызывает снижение производительности по мере роста числа наблюдателей.

Что такое Object.observe

Object.observeO.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 Наконец, мы выполнили некоторые изменения на объекте.

Если вы увидите вывод на консоли, вы увидите, что все три изменения обнаружены и зарегистрированы. На следующем снимке экрана показан результат, полученный фрагментом кода:

object.observe-пример-1

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 В дополнение к ним добавляется blockedObject.defineProperty В нашем примере сеттер, определенный для этого свойства, является простым. В типичном бизнес-приложении он может выполнять некоторые проверки и может не устанавливать значение в случае сбоя проверки. Однако я хотел, чтобы все было просто.
В качестве последнего замечания вы можете видеть, что в нашем примере уведомление отправляется только при наличии обновления.

Изменение в blocked

object.observe-пример-2

Ниже приведена живая демонстрация этого примера (не забудьте открыть консоль, чтобы увидеть результат):

Наблюдение за множественными изменениями

Иногда мы можем выполнить вычисление после того, как два или более свойства каким-либо образом изменены. Хотя мы можем уведомить оба этих изменения по отдельности с помощью уведомителя, было бы лучше отправить одно уведомление с именем пользовательского типа, чтобы указать, что оба значения изменены. Это можно сделать с помощью метода notifier.performChange() Этот метод принимает три аргумента:

  • Название пользовательского типа
  • Функция обратного вызова, выполняющая изменения. Значение, возвращаемое из этой функции, используется в объекте изменения
  • Объект, к которому применяются изменения

Давайте добавим новое свойство с именем doneTodoType Значение этого свойства указывает, завершен ли элемент задачи или нет. Когда значение donetrueblockedtrue

Следующий фрагмент определяет это свойство:

 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.otodo

 Object.observe(todo, function(changes){
  console.log(changes);
}, ['add', 'update', 'doneAndUnblocked']);

todo.blocked = true;
todo.done = true;

Приведенный выше фрагмент устанавливает значение заблокированного на truedonetrue Таким образом, он отправляет уведомление с пользовательским типом изменения. На следующем снимке экрана показаны детали объекта изменения, возвращаемого пользовательским типом:

object.observe-пример-3

Ниже приведена живая демонстрация этого примера (не забудьте открыть консоль, чтобы увидеть результат):

Наблюдение массивов

Наблюдение за массивами аналогично наблюдению за объектами. Единственное отличие состоит в том, что функция наблюдателя должна быть зарегистрирована с использованием Array.observeObject.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.oEmber также собирается использовать ее для обнаружения изменений в будущем. В Angular 2 и Aurelia реализованы функции восстановления поллиний, когда O.o

Будущее вокруг двусторонней привязки на стороне клиента будет ярче с этим замечательным дополнением к браузерам. Давайте с нетерпением ждем других браузеров, чтобы наверстать упущенное раньше!