Использование IndexedDB и руководство по яме

база данных внешний интерфейс браузер продукт IndexedDB

Обзор

В этом документе принимаетсяIndexedDBПредставлены методы использования и сценарии использования, а также даны ответы на часто задаваемые вопросы.

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

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

Причина: разработчикам необходимо постоянно хранить локально

Когда мы разработаем несколько больших страниц SPA, нам нужно будет хранить некоторые данные локально.

Когда объем данных невелик, мы можем использовать SessionStorage или LocalStorage для его хранения, но когда объем данных велик или соответствует определенным спецификациям, мы можем использовать базу данных для хранения данных.

В базе данных браузера естьweb sqlиIndexedDBдва вида. По сравнению с HTML5 устарелweb sqlРекомендуется использоватьIndexedDB.

структура

Ниже мы используем изображение, чтобы понять общую структуру IndexedDB.

аналогияsqlтип базы данных,IndexedDBБД (база данных) вsqlв БД, покаObject Store(存储空间)является数据表,Itemравно записи в таблице记录.

Использование ИндекседБД

Теперь мы основываемся наIndexedDBСтруктура хранилища представлена ​​для ознакомления с его работой, чтобы каждый мог иметь предварительное представление об этом пространстве хранения. В основном мы представляем:

  • операции с базой данных
  • Работа с таблицей данных
  • манипуляция данными

операции с базой данных

Создать или открыть базу данных

использоватьIndexedDBПервым шагом является создание или открытие базы данных. Мы используемwindow.indexedDB.open(DBName)Этот API для вызова для работы. Конкретные примеры следующие:

const request = window.indexedDB.open('test');

request.onupgradeneeded = function (event) {
    
}

request.onsuccess = function(event) {
	//request === event.target;
}
request.onerror = function(event) {}

При вызове этого интерфейса, если текущая база данных не существует, будет создана новая база данных.

Когда соединение с базой данных установлено,IDBOpenDBRequestобъект.

Когда соединение установлено успешно, оно активируетonsuccessсобытие, где параметр функцииeventизtargetсобственностьrequestобъект.

Когда база данных будет создана или версия будет обновлена, она сработаетonupgradeneededсобытие.

Обновить номер версии базы данных

window.indexedDB.openВторой параметр — это номер версии. Если не указано, номер версии по умолчанию — 1. Конкретные примеры следующие:

const request = window.indexedDB.open('test', 2);

Когда необходимо обновить базу данныхschema(模式), вам необходимо обновить номер версии. На этом этапе мы указываем номер версии выше, чем предыдущая версия, которая вызоветonupgradeneededсобытие. Точно так же, когда база данных не существует, это событие также будет запущено, и версия будет обновлена ​​до верхней версии.

Мы должны отметить, что номер версииUnsigned long longчисло, что означает, что это может быть очень большое целое число. Однако это не может быть десятичное число, иначе оно будет округлено до ближайшего целого числа, что может привести кonUpgradeneededСобытие не срабатывает (баг).

Операции с хранилищем

Создать место для хранения

Мы используемcreateObjectStoreдля создания места для хранения. использовать одновременноcreateIndexдля создания его индекса. Конкретные примеры следующие:

var request = window.indexedDB.open('test', 1);

request.onupgradeneeded = function (event) {
    var db = event.target.result;
    var objectStore = db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});

    objectStore.createIndex('name', 'name', {unique: false});
}

request.onerror = function (event) {
    alert("Why didn't you allow my web app to use IndexedDB?!");
};

Примечание: доступно только вonupgradeneededМесто для хранения создается в функции обратного вызова, а не после открытия базы данных.successСоздается в функции обратного вызова.

пройти черезcreateObjectStoreВозможность создания места для хранения. Принимает два параметра:

  1. Первый параметр, имя хранилища, которое у нас вышеcustomers.
  2. Второй параметр указывает сохраненноеkeyPathЗначение является атрибутом объекта хранилища, которое можно использовать в качестве значения ключа при получении данных о пространстве хранения.autoIncrementуказанныйkeyЯвляется ли значение автоматически увеличивающимся (когда значение ключа является целым числом от 1 до 2^53 по умолчанию).

иcreateIndexМожно установить индекс для текущего пространства хранения. Он принимает три параметра:

  1. Первый параметр, имя индекса.
  2. Второй параметр указывает, по какому атрибуту сохраненных данных строить индекс.
  3. Третье свойство, объект параметров, где свойствоuniqueзначениеtrueУказывает, что значения индекса не могут быть равными.

манипуляция данными

дела

существуетIndexedDBВ , мы также можем использовать транзакции для выполнения операций с базой данных. Транзакции имеют три режима (константы устарели):

  • readOnly, только чтение.
  • readwrite, прочти и напиши.
  • versionchange, версия базы данных меняется.

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

const transaction = db.transaction(['customers'], 'readwrite');

функция транзакцииtransactionПервый параметр — это пространство для хранения, которое необходимо связать, а второй необязательный параметр — это режим транзакции. Подобно предыдущему, он также срабатывает при успешной транзакции.onsuccessфункция, срабатывающая при сбоеonerrorфункция.

Транзакционные операции атомарны.

добавить данные

Когда пространство для хранения инициализировано, мы можем поместить данные в пространство для хранения. позвонить напрямуюaddметод может поместить данные в пространство для хранения, конкретный пример выглядит следующим образом:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var index = objectStore.index('name');

    objectStore.add({name: 'a', age: 10});
    objectStore.add({name: 'b', age: 20});
}

Примечание:addЗначение ключа второго параметра в методе находится в указанном пространстве памяти.keyPathзначение, еслиdataсодержитkeyPathvalue или это значение самоувеличивается, то этот параметр можно опустить.

Найти данные

Получить данные по определенному значению

Когда нам нужно получить данные из хранилища, мы можем использовать следующие методы:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var request = objectStore.get(1);

    request.onsuccess = function (event) {
        // 对 request.result 做些操作!
        console.log(request.result);
    };

    request.onerror = function (event) {
        // 错误处理!
    };
}

Получить данные через курсор

Когда вам нужно просмотреть данные во всем пространстве хранения, вам нужно использовать курсор. Использование курсора выглядит следующим образом:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var request = objectStore.openCursor();

    request.onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
            // 使用Object.assign方法是为了避免控制台打印时出错
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 错误处理!
    };
}

При использовании курсоров есть одно предостережение: когда курсор пересекает все пространство хранения, но не находит значения для заданного условия, он все равно сработает.onsuccessфункция.

openCursorиopenKeyCursorЕсть два параметра:

  1. Первый параметр, диапазон обхода, указывает диапазон доступа курсора. Диапазон проходит черезIDBKeyRangeспособ получения параметров.

    Ниже приведены конкретные примеры параметров диапазона перемещения:

// 匹配值 key === 1
const singleKeyRange = IDBKeyRange.only(1);

// 匹配值 key >= 1
const lowerBoundKeyRange = IDBKeyRange.lowerBound(1);

// 匹配值 key > 1
const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, true);

// 匹配值 key < 2
const upperBoundOpenKeyRange = IDBKeyRange.upperBound(2, true);

// 匹配值 key >= 1 && key < 2
const boundKeyRange = IDBKeyRange.bound(1, 2, false, true);

index.openCursor(boundKeyRange).onsuccess = function(event) {
  const cursor = event.target.result;
  if (cursor) {
    // Do something with the matches.
    cursor.continue();
  }
};

  1. Второй параметр, порядок обхода, указывает порядок, в котором перемещается курсор, и метод обработки, когда повторяется один и тот же идентификатор (поле, заданное атрибутом keyPath). изменить область действия определенной строкой (IDBCursorконстанты устарели) для получения. в:

    • next, получить все данные от начала до конца (включая дубликаты)
    • prev, извлекает все данные сзади наперед (включая дубликаты)
    • nextunique, получить данные спереди назад (за дублирующиеся данные берется только первая запись, а если индекс повторяется, то он считается повторяющимся, то же самое ниже)
    • prevunique, получить данные сзади наперед (за дублирующиеся данные берется только первый)

    Конкретный пример параметра порядка обхода выглядит следующим образом:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, false);
    var request = objectStore.openCursor(lowerBoundOpenKeyRange, IDBCursor.PREV);

    request.onsuccess = function (event) {
        var cursor = event.target.result;
        if (cursor) {
            // 使用Object.assign方法是为了避免控制台打印时出错
            console.log(Object.assign(cursor.value));
            cursor.continue();
        }
    };

    request.onerror = function (event) {
        // 错误处理!
    };
}

использовать индекс

Ранее при построении базы данных мы создали два индекса. Теперь мы также можем получать данные по индексу. Суть его по-прежнему осуществляется через API, который получал данные раньше, но исходный использовалkeyPathАтрибуты преобразуются в атрибуты, указанные в индексе. Конкретные примеры следующие:

var request = window.indexedDB.open('test', 1);

request.onsuccess = function (event) {
    var db = event.target.result;

    var transaction = db.transaction(['table1'], 'readwrite');

    var objectStore = transaction.objectStore('table1');

    var index = objectStore.index('name');

    // 第一种,get方法
    index.get('a').onsuccess = function (event) {
        console.log(event.target.result);
    }

    // 第二种,普通游标方法
    index.openCursor().onsuccess = function (event) {
        console.log('openCursor:', event.target.result.value);
    }

    // 第三种,键游标方法,该方法与第二种的差别为:普通游标带有value值表示获取的数据,而键游标没有
    index.openKeyCursor().onsuccess = function (event) {
        console.log('openKeyCursor:', event.target.result);
    }
}

изменить данные

Когда нам нужно изменить данные в хранилище, мы можем использовать следующие API:

var objectStore = transaction.objectStore("customers");

var request = objectStore.put(data);

request.onsuccess = function (event) {
    
}

Примечание:putМетоды могут не только изменять существующие данные, но и добавлять новые данные в пространство для хранения.

удалить данные

Когда нам нужно удалить бесполезные данные, мы можем сделать следующее:

var objectStore = transaction.objectStore("customers");

var request = objectStore.delete(name);

request.onsuccess = function (event) {
    
}

Обработка исключений

Когда браузер выполняет следующие операции, в indexedDB может возникнуть исключение:

  • Пользователь очищает кеш браузера
  • Место для хранения превышает предельный размер

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

Расширенное уведомление

зависит от стоимости

Тип данных, который может принимать значение ключа

существуетIndexedDBв паре ключ-значениеkeyValue может принимать следующие типы значений:

  • number
  • data
  • string
  • binary
  • array

Подробности смотрите в документацииздесь.

Тип данных, который может принимать ключевой путь

когдаkeyЗначение становится первичным ключом, т.е.keyPath, его значение может быть только следующим:

  • Blob
  • File
  • Array
  • String

Примечание. В ключевом пути не должно быть пробелов..

Подробности смотрите в документацииздесь.

Тип данных, который может принимать значение

существуетIndexedDB, value может принимать все типы значений в ECMA-262, такие как String, Date, ImageDate и т. д.

связанный с транзакцией

После того, как транзакция будет прервана, повлияет ли это на автоинкремент значения ключа?

IndexedDBЕсли значение ключа не указано, будет использоваться самоувеличивающееся значение ключа. Если транзакция прерывается в середине, автоинкремент значения ключа начнется с ключа до начала прерванной транзакции.

связанных с безопасностью

IndexedDBТакже влияет браузерТа же политика происхожденияпределы.

связанные с пользователем

Очистить кэш

Когда пользователь очищает кеш браузера, он может очиститьIndexedDBсвязанные данные.

разрешение на доступ

Некоторые браузеры, такие как режим конфиденциальности мобильной версии Safari, получают доступIndexedDB, могут возникать исключения из-за отсутствия разрешений (как и LocalStorage), и требуется обработка исключений.

Суммировать

IndexedDBОн играет незаменимую роль в локальном хранилище и является альтернативой реляционным базам данных.web sqlпродукты, способные хранить большие объемы данных. Во многих сценариях, где требуется автономное хранилище, оно может оказать нам эффективную поддержку.

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

использованная литература