Mithril — лёгкий и производительный JavaScript-фреймворк,
ориентированный на создание одностраничных приложений. Для реализации
offline-поддержки критически важно понимать, как данные хранятся и
синхронизируются с сервером. В контексте Mithril ключевую роль играет
модель данных и её взаимодействие с локальным
хранилищем браузера, таким как localStorage,
IndexedDB или сервис-воркеры.
Offline-поддержка обычно включает три компонента:
Для кеширования статических ресурсов чаще всего используют Service Worker API. В Mithril структура приложения позволяет легко интегрировать сервис-воркер:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(() => {
console.log('Service Worker зарегистрирован');
});
}
Внутри sw.js описывается логика кэширования:
const CACHE_NAME = 'app-cache-v1';
const urlsToCache = [
'/',
'/index.html',
'/app.js',
'/style.css'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => cache.addAll(urlsToCache))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
Такой подход обеспечивает доступность приложения даже при отсутствии интернет-соединения.
Mithril использует реактивные модели через функции и объекты, что упрощает интеграцию с локальными хранилищами. Для offline-хранения чаще всего применяются:
Пример использования localStorage с моделью Mithril:
const TodoModel = {
list: m.prop(JSON.parse(localStorage.getItem('todos') || '[]')),
add(todo) {
const current = this.list();
current.push(todo);
this.list(current);
localStorage.setItem('todos', JSON.stringify(current));
}
};
Для IndexedDB рекомендуется использовать промисифицированные обёртки,
такие как idb. Это позволяет хранить и извлекать данные
асинхронно, без блокировки UI.
Синхронизация данных между локальным хранилищем и сервером может
выполняться по событию online или через периодические
запросы. Mithril предоставляет удобный метод m.request,
который поддерживает промисы и легко интегрируется с локальными
моделями:
function syncTodos() {
const todos = TodoModel.list();
m.request({
method: 'POST',
url: '/api/todos/sync',
body: todos
}).then(serverResponse => {
// Обновление локального хранилища на основе ответа сервера
TodoModel.list(serverResponse);
localStorage.setItem('todos', JSON.stringify(serverResponse));
}).catch(err => {
console.error('Синхронизация не удалась', err);
});
}
window.addEventListener('online', syncTodos);
Ключевой принцип — двусторонняя синхронизация: изменения в локальном хранилище должны отправляться на сервер, а серверные обновления — сохраняться локально. Для этого применяются методы слияния данных, проверка временных меток и версий объектов.
При offline-режиме возможны конфликты, если одни и те же данные изменяются на клиенте и сервере. Стратегии разрешения конфликтов:
Пример простого слияния по полям для задач:
function mergeTodos(localTodos, serverTodos) {
const merged = [...serverTodos];
localTodos.forEach(local => {
const index = merged.findIndex(s => s.id === local.id);
if (index !== -1) {
merged[index] = { ...merged[index], ...local };
} else {
merged.push(local);
}
});
return merged;
}
Mithril автоматически обновляет представление при изменении данных модели. Для offline-поддержки это важно, чтобы изменения локальных данных сразу отображались пользователю:
m.mount(document.body, {
view() {
return m('ul', TodoModel.list().map(todo => m('li', todo.text)));
}
});
Каждое добавление или синхронизация данных вызывает обновление
TodoModel.list(), и интерфейс перерисовывается
автоматически.
online для немедленной
синхронизации.Offline-поддержка и синхронизация в Mithril строятся вокруг моделей, сервис-воркеров и локального хранилища, обеспечивая быстрый и стабильный интерфейс независимо от состояния сети.