В вебе есть множество API для информирования о том, что происходит в вашем приложении. Вы можете мониторить множество вещей и наблюдать практически любые типы изменений.

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

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

Прослушиваем события DOM (как нативные, так и кастомные):

// user scrolls the page.
window.addEventListener('scroll', e => { ... });

el.addEventListener('focus', e => { ... }); // el is focused. img.addEventListener('load', e => { ... }); // img is done loading. 

// user types into input.
input.addEventListener('input', e => { ... }); 

// catch custom event fired on el.
el.addEventListener('custom-event', e => { ... });

Прослушиваем модификацию DOM:

const observer = new MutationObserver(mutations => { ... }); observer.observe(document.body, {
  childList: true,
  subtree: true,
  attributes: true,
  characterData: true
});

Узнаем об изменении URL:

window.onhashchange = e => console.log(location.hash); window.onpopstate = e => console.log(document.location, e.state);

Узнаем о работе приложения в полноэкранном режиме (подробнее):

document.addEventListener('fullscreenchange', e => {
  console.log(document.fullscreenElement)
});

Узнаем о поступлении сообщений по WebRTC:

// Cross-domain / window /worker.
window.onmessage = e => { ... }; 

// WebRTC
const dc = (new RTCPeerConnection()).createDataChannel(); dc.onmessage = e => { ... };

Узнаем об ошибках на клиентской стороне (подробнее):

// Client-size error?
window.onerror = (msg, src, lineno, colno, error) => { ... };

// Unhandled rejected Promise?
window.onunhandledrejection = e => console.log(e.reason);

Отслеживаем изменение ориентации экрана устройства (подробнее):

const media = window.matchMedia('(orientation: portrait)'); media.addListener(mql => console.log(mql.matches)); 

// Orientation of device changes.
window.addEventListener('orientationchange', e => {
  console.log(screen.orientation.angle)
});

Отслеживаем изменения в сетевом соединении (подробнее):

// Online/offline events.
window.addEventListener('online', e => {
  console.assert(navigator.onLine)
});
window.addEventListener('offline', e => {
  console.assert(!navigator.onLine)
});

// Network Information API navigator.connection.addEventListener('change', e => {
  console.log(navigator.connection.type,
              navigator.connection.downlinkMax);
});

Отслеживаем состояние заряда батареи устройства (подробнее):

navigator.getBattery().then(batt => { 
  batt.addEventListener('chargingchange', e => {
    console.log(batt.charging);
  });
  batt.addEventListener('levelchange',e => {
    console.log(batt.level);
  });
  batt.addEventListener('chargingtimechange', e => {
    console.log(batt.chargingTime);
  }); 
  batt.addEventListener('dischargingtimechange', e => {
    console.log(batt.dischargingTime);
  });
});


Узнаем о видимости/нахождении в фокусе вкладки или страницы (подробнее):

document.addEventListener('visibilitychange', e => {
  console.log(document.hidden)
});

Узнаем о смене пользователем расположения:

navigator.geolocation.watchPosition(pos => console.log(pos.coords));

Узнаем о изменении разрешений на использование нужного API (подробнее):

const q = navigator.permissions.query({name: 'geolocation'}); q.then(permission => {
  permission.addEventListener('change', e => {
    console.log(e.target.state);
  });
});

Узнаем об обновлении другой вкладкой локального хранилища или хранилища сессии:

window.addEventListener('storage', e => alert(e));

Узнаем о появлении или покидании элементом области видимости (то есть о видимости элемента, подробнее):

const observer = new IntersectionObserver(changes => {
  ...
}, {threshold: [0.25]}); observer.observe(document.querySelector('#watchMe'));

Узнаем, когда браузер находится в “ленивом” режиме (и готов выполнить какую-нибудь дополнительную работу, подробнее):

requestIdleCallback(deadline => { ... }, {timeout: 2000});

Узнаем о загрузке браузером ресурса или о записи метрики User Timing (подробнее):

const observer = new PerformanceObserver(list => {
  console.log(list.getEntries());
});
observer.observe({entryTypes: ['resource', 'mark', 'measure']});

Узнаем об изменении свойств объекта (включая свойства DOM, подробнее):

// Observe changes to a DOM node's .textContent.
// From gist.github.com/ebidel/d923001dd7244dbd3fe0d5116050d227 

const proxy = new Proxy(document.querySelector('#target'), { 
  set(target, propKey, value, receiver) {
    if (propKey === 'textContent') {
      console.log('textContent changed to: ' + value);
    }
    target[propKey] = value;
  }
});
proxy.textContent = 'Updated content!';

Круто! И, главное, что еще большее количество API находится в разработке.

Я предполагаю, что вы могли бы классифицировать некоторые из этих примеров как техники и паттерны (например, реагирование на события DOM). Однако многие совершенно новые API создавались с определенной целью: измерение производительности, информирование о заряде батареи, состояния онлайн или офлайн.

Это действительно впечатляет, к каким вещам у веб-разработчиков есть доступ в наши дни. API есть практически для всего.