Dexie.js предоставляет слой абстракции над IndexedDB, где управление соединением с базой данных становится управляемым жизненным циклом, включающим создание экземпляра, открытие, миграции схемы и фазу готовности. Центральное место в этом процессе занимает открытие соединения и событие готовности, через которое формируется точка синхронизации всей логики инициализации.
Создание экземпляра базы данных в Dexie.js не приводит к немедленному открытию соединения. Объект создаётся в состоянии отложенной инициализации:
import Dexie from "dexie";
const db = new Dexie("app_database");
На этом этапе определена только сущность базы, но отсутствует активное соединение с IndexedDB. Схема таблиц обычно задаётся до открытия:
db.version(1).stores({
users: "++id,name,email",
posts: "++id,userId,title"
});
Важно, что сама по себе конфигурация версии не инициирует
I/O-операции. Открытие происходит либо неявно при первом обращении к
таблице, либо явно через вызов open().
Метод open() запускает полный цикл инициализации базы
данных:
await db.open();
При вызове open() выполняется последовательность
операций:
Возвращаемый Promise резолвится только после завершения всех шагов,
включая выполнение обработчиков ready.
Процесс открытия можно разделить на несколько фаз:
onupgradeneeded (если требуется)В этой цепочке событие готовности играет роль синхронизирующего барьера между завершением инициализации и началом пользовательских операций.
Событие ready в Dexie.js вызывается в момент, когда база
данных уже успешно открыта, но до окончательного завершения
open() в пользовательском коде. Это создаёт возможность
выполнить асинхронные операции, которые должны быть завершены до начала
работы приложения с данными.
db.on("ready", async (dbInstance) => {
const count = await dbInstance.users.count();
if (count === 0) {
await dbInstance.users.bulkAdd([
{ name: "Initial User", email: "init@example.com" }
]);
}
});
Ключевое свойство ready заключается в том, что он может
задерживать завершение открытия базы. Если обработчик возвращает
Promise, выполнение db.open() приостанавливается до его
завершения.
Поведение события зависит от возвращаемого значения:
db.on("ready", () => {
console.log("База открыта");
});
В этом случае событие используется только для побочных эффектов, и открытие не задерживается.
db.on("ready", async (dbInstance) => {
await dbInstance.table("settings").toArray();
});
Здесь возвращаемый Promise влияет на момент завершения
open(). Это позволяет гарантировать, что база не начнёт
обслуживать запросы до завершения подготовки данных.
Метод open() и событие ready решают разные
задачи.
open():
ready:
open()Таким образом, ready — это точка расширения внутри
процесса открытия, а open() — внешний управляющий
механизм.
После закрытия соединения через db.close() повторный
вызов open() снова запускает цикл инициализации. При этом
обработчики ready вызываются заново:
db.close();
await db.open();
Каждое открытие формирует новый жизненный цикл, включая повторное
выполнение миграций (если изменилась версия) и повторный вызов всех
подписок ready.
Одна из распространённых моделей использования ready —
ленивое заполнение или подготовка кэша:
db.on("ready", async (dbInstance) => {
const hasConfig = await dbInstance.settings.get("config");
if (!hasConfig) {
await dbInstance.settings.put({
key: "config",
value: { theme: "dark" }
});
}
});
Такая логика выполняется строго до начала работы приложения с данными, что исключает состояние частичной инициализации.
Во время выполнения обработчика ready возможно
использование таблиц, однако важно учитывать, что система ещё находится
в фазе открытия. Dexie гарантирует корректную сериализацию операций, но
чрезмерно тяжёлые операции внутри ready могут увеличить
время старта приложения.
Особенность заключается в том, что ready выполняется в
контексте уже созданного соединения, но до финального разрешения Promise
open().
Если во время открытия происходит ошибка версии, повреждение
хранилища или блокировка другой вкладкой, ready не будет
вызван. Вместо этого срабатывает обработка ошибок:
db.on("error", (error) => {
console.error("Ошибка базы:", error);
});
Таким образом, ready гарантирован только при успешном
открытии соединения.
Наиболее характерные сценарии применения включают:
Каждый из этих сценариев требует выполнения логики строго до начала основного потока операций чтения и записи.
В жизненном цикле Dexie.js событие ready располагается
после миграции схемы, но до завершения open():
Такое расположение делает его ключевой точкой для синхронизации состояния приложения с физическим хранилищем.
Использование ready позволяет избежать гонок между
первым запросом к таблице и завершением подготовки базы. Вместо
разрозненных проверок в разных частях приложения, вся логика
консолидации состояния размещается в одном месте жизненного цикла
открытия.
db.on("ready", async (dbInstance) => {
await Promise.all([
dbInstance.users.count(),
dbInstance.posts.count()
]);
});
Такая модель обеспечивает детерминированное состояние базы к моменту начала основной работы с данными.