Push-уведомления позволяют веб-приложениям уведомлять пользователя о событиях в реальном времени, даже если вкладка с приложением не активна. В контексте JavaScript и фреймворка Mithril процесс их интеграции опирается на стандарты Service Worker и Push API, а также на эффективное управление состоянием в компонентах Mithril.
Service Worker — это фоновый скрипт, который работает независимо от страницы. Он отвечает за получение push-сообщений и их отображение. Для регистрации Service Worker используется следующий код:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker зарегистрирован', registration);
})
.catch(error => {
console.error('Ошибка регистрации Service Worker', error);
});
}
Ключевой момент: Service Worker должен находиться в корневой
директории или иметь корректный scope, чтобы управлять
необходимой областью сайта.
Push-подписка создается с использованием PushManager.
Основные шаги:
Пример реализации:
async function subscribeUser() {
if (!('PushManager' in window)) return;
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('<VAPID_PUBLIC_KEY>')
});
console.log('Подписка создана:', subscription);
return subscription;
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
const rawData = window.atob(base64);
return new Uint8Array([...rawData].map(char => char.charCodeAt(0)));
}
Важно: userVisibleOnly: true гарантирует, что каждое
push-сообщение будет отображаться пользователю в виде уведомления.
Service Worker получает push-сообщения и отображает их с помощью
Notification API. Пример sw.js:
self.addEventListener('push', event => {
const data = event.data.json();
const options = {
body: data.body,
icon: '/icon.png',
badge: '/badge.png',
data: { url: data.url }
};
event.waitUntil(
self.registration.showNotification(data.title, options)
);
});
self.addEventListener('notificationclick', event => {
event.notification.close();
event.waitUntil(
clients.matchAll({ type: 'window' }).then(clientList => {
for (const client of clientList) {
if (client.url === event.notification.data.url && 'focus' in client) {
return client.focus();
}
}
if (clients.openWindow) {
return clients.openWindow(event.notification.data.url);
}
})
);
});
Особенности:
event.waitUntil гарантирует завершение асинхронных
операций до того, как Service Worker завершит обработку события.clients.matchAll и clients.openWindow
управляют открытием или фокусировкой вкладок при клике на
уведомление.Mithril предоставляет легковесный подход к построению интерфейса, где состояние можно связать с push-уведомлениями через компоненты и сервисы.
Пример сервиса для работы с push-подпиской:
const PushService = {
subscription: null,
async init() {
if (!('serviceWorker' in navigator)) return;
const registration = await navigator.serviceWorker.ready;
this.subscription = await registration.pushManager.getSubscription();
},
async subscribe() {
if (!this.subscription) {
this.subscription = await subscribeUser();
}
},
async unsubscribe() {
if (this.subscription) {
await this.subscription.unsubscribe();
this.subscription = null;
}
}
};
Компонент Mithril для управления подпиской:
const PushComponent = {
view() {
return m('div', [
m('button', { onclick: () => PushService.subscribe() }, 'Подписаться на уведомления'),
m('button', { onclick: () => PushService.unsubscribe() }, 'Отписаться')
]);
}
};
Преимущество: все асинхронные операции скрыты внутри сервиса, а компонент сосредоточен исключительно на интерфейсе.
Mithril позволяет хранить состояние подписки в глобальном объекте
сервиса и обновлять интерфейс через m.redraw(). Пример:
const PushStatus = {
subscribed: false
};
async function toggleSubscription() {
if (PushStatus.subscribed) {
await PushService.unsubscribe();
PushStatus.subscribed = false;
} else {
await PushService.subscribe();
PushStatus.subscribed = true;
}
m.redraw();
}
Использование глобального состояния облегчает интеграцию push-уведомлений с другими частями приложения и упрощает тестирование.
safari.pushNotification.Push-уведомления в Mithril строятся на четком разделении задач: Service Worker обрабатывает фоновые события, сервис управляет подпиской, компоненты отображают состояние. Такая структура обеспечивает масштабируемость и простоту сопровождения приложений с реальными уведомлениями.