внешнее хранилище
Все мы знаем, что при фронтенд-разработке иногда некоторые данные необходимо хранить локально во фронтенде из-за определенных требований, например, для оптимизации производительности некоторые часто используемые данные хранятся локально, чтобы их можно было напрямую берется из локального, когда понадобится позже.Нет необходимости делать запросы к бэкенду.Кроме того, для предотвращения CSRF-атак бэкенд отдает токен на фронтенд, а фронтенд должен хранить этот токен локально.После что, каждый запрос должен приносить этот токен.И так далее.
И этих потребностей нельзя избежать, чтобы создать направление фронтенд-разработки--внешнее хранилище
В «древние времена» внешнего интерфейса у нашего внешнего интерфейса был только один способ хранения данных, и этоCookie
.ноCookie
Хотя его можно использовать в качестве внешнего хранилища, у него также есть много ограничений.Во-первых, его объем памяти составляет всего 4 КБ, а во-вторых, его эффективное время хранения ограничено, а затем естьCookie
Данные в файле будут приноситься с вами каждый раз, когда вы делаете запрос.Он будет бессмысленно увеличивать данные каждый раз, когда вы делаете запрос.Наконец, это еще и самый важный момент.Cookie
В начале разработки мы не просто храним данные во внешнем интерфейсе, сайт только проверяет личность пользователя.Cookie
Локальное хранилище — это всего лишь средство, вы можете прочитать другую мою статью на эту тему---В эпоху HTML5 повторно распознавать файлы cookie
Таким образом, используйтеCookie
В качестве внешнего хранилища есть много недостатков, поэтому после непрерывных усилий сообщества внешнего интерфейса в HTML5 есть реальное решение для внешнего хранилища.Web Storage
. Он делится на два вида, один из которых предназначен для постоянного хранения.localStorage
, один сохраняется во время сеансаsessionStorage
.В сравненииCookie
,Web Storage
Преимущества очевидны:
- Больше места для хранения, размер 5M
- Отправка запросов в браузере не принесет
web Storage
данные в- более дружественный API
- Можно сделать постоянное хранилище (localStorage).
Все это выглядит идеально, но по мере того, как интерфейс продолжает развиваться,web Storage
Есть и неподходящие места:
- В связи с непрерывным развитием веб-приложений размер хранилища в 5 МБ недостаточен для некоторых крупных веб-приложений.
web Storage
хранить толькоstring
тип данных.Object
Данные типа можно использовать только в первую очередьJSON.stringify()
Преобразуйте его и сохраните.
Исходя из вышеперечисленных причин, фронтенд-сообщество предложило концепцию хранения базы данных браузера.Web SQL Database
иindexedDB(索引数据库)
является реализацией этой концепции.Среди нихWeb SQL Database
В настоящее время от него в основном отказались, поэтому реализация текущей базы данных основного браузераindexedDB(索引数据库)
, это то, что мы собираемся представитьРешение для внешнего хранилища нового поколения — indexedDB
Что такое indexedDB
Введение в indexedDB
IndexedDB — это способ хранения больших объемов данных с помощью браузера. Создаваемые им данные можно запрашивать и использовать в автономном режиме. IndexedDB — очень эффективное решение для программ, которым необходимо хранить большие объемы данных или которые необходимо использовать в автономном режиме. -- - МДН
Концепция indexedDB
С помощью IndexedDB вы можете хранить или извлекать данные, проиндексированные с помощью ключа. Вы можете изменить данные в транзакции. Как и большинство решений для веб-хранилищ, indexedDB также соответствует политике единого источника, поэтому вы можете получить доступ только к данным, хранящимся в том же домене, но не в других доменах.
API включает два вида асинхронного (асинхронного) API и синхронного (синхронного) API. Асинхронные API подходят для большинства случаев, а синхронные API должны использоваться с WebWorkers.В настоящее время ни один из основных браузеров не поддерживает синхронные API. Даже если синхронные API поддерживаются, в большинстве случаев вы будете использовать асинхронные API.
IndexedDB является заменой базы данных WebSQL. Организация W3C отказалась от webSql 18 ноября 2010 г. Разница между IndexedDB и WebSQL заключается в том, что WebSQL является реляционной базой данных (сложной), а IndexedDB — базой данных типа "ключ-значение" (простой и простой в использовании).
Выше естьMDNЗнакомство с IndexedDB выше. Проще говоря, indexedDB — это интерфейсная база данных с ключом и значением, основанная на транзакционных операциях. Большинство ее API-интерфейсов являются асинхронными.
Использование indexedDB
Создайте базу данных indexedDB
const request = indexedDB.open('myDatabase', 1);
request.addEventListener('success', e => {
console.log("连接数据库成功");
});
request.addEventListener('error', e => {
console.log("连接数据库失败");
});
В приведенном выше коде мы используемindexedDB.open()
СоздаватьindexedDB
база данных.open()
Метод принимает два параметра. Первый — это имя базы данных, а второй — номер версии базы данных.IDBOpenDBRequest
Объекты используются для управления базой данных.open()
Имя базы данных первого параметра,open()
Сначала он узнает, существует ли уже база данных локально. Если да, то он напрямую вернет базу данных. Если нет, то сначала создаст базу данных, а затем вернет ее. Для второго параметра номер версии это необязательный параметр, если не передано, значение по умолчанию равно 1. Но если оно передано, оно должно быть целым числом.
мимоходомindexedDB.open()
метод получения объекта базы данныхIDBOpenDBRequest
Мы можем контролировать этот объектsuccess
события иerror
событие для выполнения соответствующего действия.
Создать репозиторий объектов
После того, как у нас есть другая база данных, мы хотим хранить данные, но базы данных недостаточно, нам также нужно хранилище объектов.Хранилище объектов является основой базы данных indexedDB, которая аналогична концепции таблиц в MySQL.
Для создания репозитория объектов необходимо
upgradeneeded
событие, покаupgradeneeded
Событие сработает только при обновлении номера версии. Это связано с тем, чтоindexedDB API
Изменения в хранилище данных в БД не допускаются в той же версии
const request = indexedDB.open('myDatabase', 2);
request.addEventListener('upgradeneeded', e => {
const db = e.target.result;
const store = db.createObjectStore('Users', {keyPath: 'userId', autoIncrement: false});
console.log('创建对象仓库成功');
});
В приведенном выше коде мы слушаемupgradeneeded
событие и использовать, когда это событие срабатываетcreateObjectStore()
метод создает репозиторий объектов.createObjectStore()
Метод принимает два параметра. Первый — это имя хранилища объектов. В одной и той же базе данных имя хранилища не может повторяться. Второй — необязательный параметр. Он используется для указания первичного ключа данных и необходимости автоматическое увеличение первичного ключа.
создать транзакцию
ОК Теперь, когда у нас есть база данных и хранилище объектов, можем ли мы хранить данные. Извините, но нет. Нам не хватает еще одного последнего элемента — транзакций.
что такое транзакция
Транзакция базы данных обычно состоит из последовательности операций чтения/записи в базу данных. Он существует для двух целей:
- Предоставляет способ восстановления последовательности операций базы данных после сбоя до нормального состояния, а также позволяет базе данных оставаться согласованной даже в ненормальном состоянии.
- Когда несколько приложений одновременно обращаются к базе данных, между этими приложениями может быть предусмотрен метод изоляции, чтобы предотвратить вмешательство друг друга в операции друг друга.
Не всякая последовательность операций над базой данных является транзакцией базы данных. Транзакции базы данных имеют следующие четыре характеристики, которые традиционно называют характеристиками ACID.
- Атомарность: транзакция выполняется как единое целое, и либо все операции над базой данных, содержащиеся в ней, либо ни одна из них не выполняются.
- Непротиворечивость: транзакция должна обеспечивать изменение состояния базы данных из одного согласованного состояния в другое. Непротиворечивое состояние означает, что данные в базе данных должны удовлетворять ограничениям целостности.
- Изоляция: при одновременном выполнении нескольких транзакций выполнение одной транзакции не должно влиять на выполнение других транзакций.
- Долговечность: изменения базы данных совершенными транзакциями должны постоянно храниться в базе данных.
Вышеприведенное объяснение транзакций базы данных в Википедии. Короче говоря, транзакция — это ограничение, используемое для обеспечения того, чтобы все операции базы данных выполнялись успешно или все терпели неудачу. Например, при изменении нескольких фрагментов данных первые несколько были успешными. из средних не удалось.В это время, если это операция базы данных на основе транзакций, то база данных должна сбросить предыдущую модификацию данных и отказаться от последующей модификации данных.Возвращать ошибку напрямую, и никакие данные не изменяются.
const request = indexedDB.open('myDatabase', 3);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
});
В приведенном выше коде мы используемtransaction()для создания транзакции.transaction()
Принимает два параметра: первый — это имя хранилища объектов, которым вы хотите управлять, а второй — созданный вами режим транзакции.readonly
Над хранилищем объектов можно выполнять только операции чтения, но нельзя выполнять операции записи.readwrite
Выполнять операции чтения и записи.
оперативные данные
Итак, теперь, когда у нас есть база данных, хранилище объектов и транзакция, мы, наконец, можем хранить данные.
- add() : добавить данные. Получает параметр для объекта, который необходимо сохранить в хранилище объектов.
- put() : добавить или изменить данные. Получает параметр для объекта, который необходимо сохранить в хранилище объектов.
- получить() : получить данные. Получает параметр, который является значением первичного ключа данных, которые необходимо получить.
- удалить() : удалить данные. Получает параметр, который является значением первичного ключа данных, которые необходимо получить.
Функции add и put аналогичны, разница в том, что когда put сохраняет данные, если первичный ключ данных уже имеет такой же первичный ключ в базе данных, он изменит объект, соответствующий первичному ключу в базе данных, и используйте add для сохранения данных, если первичный ключ уже существует, сохранение не удастся.
добавление данных
const request = indexedDB.open('myDatabase', 3);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
const store = tx.objectStore('Users');
// 保存数据
const reqAdd = store.add({'userId': 1, 'userName': '李白', 'age': 24});
reqAdd.addEventListener('success', e => {
console.log('保存成功')
})
});
получить данные
const request = indexedDB.open('myDatabase', 3);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
const store = tx.objectStore('Users');
// 获取数据
const reqGet = store.get(1);
reqGet.addEventListener('success', e => {
console.log(this.result.userName); // 李白
})
});
удалить данные
const request = indexedDB.open('myDatabase', 3);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
const store = tx.objectStore('Users');
// 删除数据
const reqDelete = store.delete(1);
reqDelete.addEventListener('success', e => {
console.log('删除数据成功'); // 李白
})
});
использовать курсор
Выше мы используемget()
Метод передает первичный ключ для получения данных, но он может получить только один фрагмент данных. Что, если мы хотим получить несколько фрагментов данных. Мы можем использовать курсор для получения данных в интервале.
Чтобы использовать курсор, нам нужно использоватьopenCursor()Метод Создать монету Открыть.openCursor()
Метод принимает два параметра.
openCursor(range?: IDBKeyRange | number | string | Date | IDBArrayKey, direction?: IDBCursorDirection): IDBRequest;
Первый — это диапазон, диапазон может бытьIDBKeyRange
Объект Создается следующим образом.
// boundRange 表示主键值从1到10(包含1和10)的集合。
// 如果第三个参数为true,则表示不包含最小键值1,如果第四参数为true,则表示不包含最大键值10,默认都为false
var boundRange = IDBKeyRange.bound(1, 10, false, false);
// onlyRange 表示由一个主键值的集合。only() 参数则为主键值,整数类型。
var onlyRange = IDBKeyRange.only(1);
// lowerRaneg 表示大于等于1的主键值的集合。
// 第二个参数可选,为true则表示不包含最小主键1,false则包含,默认为false
var lowerRange = IDBKeyRange.lowerBound(1, false);
// upperRange 表示小于等于10的主键值的集合。
// 第二个参数可选,为true则表示不包含最大主键10,false则包含,默认为false
var upperRange = IDBKeyRange.upperBound(10, false);
Вторым параметром является направление, в основном это следующие
- следующий : данные в курсоре сортируются в порядке возрастания по значению первичного ключа, и считываются данные с тем же значением первичного ключа.
- nextunique : данные в курсоре сортируются в порядке возрастания по значению первичного ключа, и только первые данные считываются, если значение первичного ключа равно
- prev : данные в курсоре сортируются в порядке убывания по значению первичного ключа, и считываются данные с тем же значением первичного ключа.
- prevunique: данные в курсоре сортируются в порядке убывания по значению первичного ключа, только первые данные считываются, если значение первичного ключа равно
Давайте посмотрим полный пример
const request = indexedDB.open('myDatabase', 4);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
const store = tx.objectStore('Users');
const range = IDBKeyRange.bound(1,10);
const req = store.openCursor(range, 'next');
req.addEventListener('success', e => {
const cursor = this.result;
if(cursor){
console.log(cursor.value.userName);
cursor.continue();
}else{
console.log('检索结束');
}
})
});
В приведенном выше коде, если извлекаются данные, соответствующие условиям, мы можем:
- использовать
cursor.value
получить данные.- использовать
cursor.updata()
обновить данные.- использовать
cursor.delete()
удалить данные.- использовать
cursor.continue()
Прочитайте следующую часть данных.
показатель
В приведенном выше коде мы используем первичный ключ для получения данных, однако во многих случаях мы не знаем, какой первичный ключ нужных нам данных, и знаем общее условие, например, пользователи старше 20 лет. лет. В настоящее время нам нужно использоватьпоказатель.для условного поиска.
создать индекс
Мы используем репозиторий объектовcreateIndex()способ создания индекса.
createIndex(name: string, keyPath: string | string[], optionalParameters?: IDBIndexParameters): IDBIndex;
createIndex()
Метод принимает три параметра:
-
первый параметр
name
является именем индекса и не может повторяться. -
второй параметр
keyPath
Это свойство, которое вы хотите индексировать в объекте хранилища, который может быть одним значением ключа или массивом, содержащим набор значений ключа. -
третий параметр
optionalParameters
необязательный параметр объекта{unique, multiEntry}
- уникальный: используется для указания, может ли значение индекса повторяться, если оно истинно, это означает, что оно не может быть одинаковым, если оно ложно, это означает, что оно может быть одинаковым.
- multiEntry: когда второй параметр
keyPath
является массивом.multiEntry
Если true, то для каждого элемента массива будет создан индекс, если false, то в качестве индекса будет использоваться весь массив.keyPath
значение, добавьте индекс.
Давайте рассмотрим полный пример, где мы создаем индекс возраста пользователя.
const request = indexedDB.open('myDatabase', 5);
request.addEventListener('upgradeneeded', e => {
const db = e.target.result;
const store = db.createObjectStore('Users', {keyPath: 'userId', autoIncrement: false});
const idx = store.createIndex('ageIndex','age',{unique: false})
});
Итак, мы создаем файл index.
использовать индекс
После создания индекса мы можем его использовать.index
метод, получить объект индекса, передав имя индекса.
const index = store.index('ageIndex');
Затем мы можем использовать этот индекс, например, мы хотим получить данные старше 20 лет и отсортировать их в порядке возрастания.
const request = indexedDB.open('myDatabase', 4);
request.addEventListener('success', e => {
const db = e.target.result;
const tx = db.transaction('Users','readwrite');
const store = tx.objectStore('Users');
const index = store.index('ageIndex');
const req = index.openCursor(IDBKeyRange.lowerBound(20), 'next');
req.addEventListener('success', e => {
const cursor = e.target.result;
if(cursor){
console.log(cursor.value.age);
cursor.continue();
}else{
console.log('检索结束');
}
})
});
совместимость с indexedDB
Выше приведено некоторое поверхностное резюме indexedDB, надеюсь оно будет всем полезно.Если в тексте есть какие-то неуместности, пожалуйста, исправьте, спасибо.
Использованная литература:
Мой личный URL: wangyiming.info