⚠️Эта статья является первой подписанной статьей сообщества Nuggets, и её перепечатка без разрешения запрещена.
задний план
Когда наша веб-страница обновится, все данные на странице будут очищены. При поиске на некоторых веб-сайтах, даже если вы закроете браузер, на странице все еще будут данные, когда вы откроете ее в следующий раз, как показано на рисунке ниже для простой функции записи поиска.Когда пользователь выполняет поиск, все записи будут быть сохранены. , независимо от того, обновляете ли вы или перезапускаете браузер, история поиска по-прежнему отображается на странице.
Эта серия требований может быть достигнута с помощью технологии хранения браузера. В этой статье давайте узнаем о технологии хранения в браузере.WebStorage
, всестороннее понимание его базового и расширенного использования, а также как использовать эти методы для отработки двух распространенных сценариев. Представляя метод использования, я также инкапсулирую工具类
Способ унифицировать все методы вызова, изучив это, может сделать его более удобным для вас в развитии бизнеса.
Почему стоит выбрать WebStorage?
Мы знаем, что распространенные методы облегченного хранения браузера включаютCookie
а такжеWebStorage
. Итак, почему мы выбираемWebStorage
вместоCookie
Шерстяная ткань?
первый,WebStorage
По сравнению с файлами cookie они более удобны в использовании, и больше нет необходимости преднамеренно инкапсулировать некоторые библиотеки инструментов для упрощения вызовов некоторых общих операций, хотя на рынке уже есть много зрелых решений, помогающих нам в этом.
Второй,chrome(80+)
Браузеры блокируют все по умолчанию三方Cookie
Это больше не шокирует. С этим изменениемCookie
Без сомнения, была отрезана еще одна мощная рука.
Для тех из вас, кто не знает, эта статья сильно написана Amway, которая анализирует ее очень подробно.Когда браузер полностью отключает сторонние файлы cookie.
Кроме того, используйтеCookie
Также необходимо решить следующие проблемы:
- Сохраненные данные слишком малы,
Cookie
Размер хранилища составляет всего4k
, если вам нужно хранить много данных, то очевидно, что это не может удовлетворить ваши потребности, и вообще никто этим не занимается. - всегда носить с собой
HTTP请求头
, будет некоторое взаимодействие с сервером, когда я просто сохраняю некоторые локальные данные, это, очевидно, приведет к потере производительности.
а такжеWebStorage
Основной функцией браузера является временное и постоянное хранение данных на стороне клиента, и он не принимает непосредственного участия в общении и взаимодействии со стороны сервера, поэтому вполне может избежать некоторых угроз безопасности, связанных с угоном. В то же время он также имеет хорошую емкость хранилища, которую можно использовать для большинства сценариев приложений, и каждое хранилище монтируется в соответствующем пространстве, а соответствующие данные управляются независимо друг от друга, что не вызовет строковых данных и неверные данные какие-то проблемы.
Исходя из этого, если есть какие-то данные, которые нужно хранить локально, лучше всего использоватьWebStorage
как основной выбор для хранения.
Основное использование
В этой главе я познакомлю вас с некоторыми базовыми навыками использования webStorage с точки зрения класса пакетного инструмента. Здесь также поделитесь ссылкой на адрес онлайн-источника:Кодекс практики упаковки при хранении
Затем в инструменте отладки браузераApplication
В меню вы можете увидеть слеваStorage
Отладочная версия, в которой мы проходимAPI
Здесь можно отладить значение, сохраненное в хранилище.
Поддержка среды и инициализация
Первый шаг должен состоять в том, чтобы выполнить некоторые проверки окружающей среды перед запуском, иначе он будет недоступен в некоторых браузерах, которые не поддерживают эти функции.Это можно найти в caniuseОзнакомьтесь с некоторыми уровнями поддержки браузеров здесь.
В наш код мы также должны добавить слой отказоустойчивого суждения.Если нам нужно сделать его совместимым, мы можем выполнить деградацию обработки. Такие какCookie
илиIE6中
изuserData持久化用户数据
.
Ниже приведено относительно простое суждение, которое также можно инкапсулировать в простую вызываемую функцию. Выдает какую-то ошибку в консоль, если браузер ее не поддерживает.
class CustomStorage {
private readStorage: Storage
constructor () {
if (!window) {
throw new Error('当前环境非浏览器,无法消费全局window实例。')
}
if (!window.localStorage) {
throw new Error('当前环境非无法使用localStorage')
}
if (!window.sessionStorage) {
throw new Error('当前环境非无法使用sessionStorage')
}
}
}
Используйте, когда среда поддерживаетWebStorage
При условии , вы можете инициализировать некоторые данные по умолчанию, выберите, какие из них использовать здесьStorage
и сохраните конфигурацию.
interface StorageBootStrapConfig {
/** 当前环境 */
mode: 'session' | 'local',
/** 超时时间 */
timeout: number
}
/**
* 初始化Storage的数据
* @param config StorageBootStrapConfig
*/
bootStrap (config: StorageBootStrapConfig): void {
switch (config.mode) {
case 'session':
this.readStorage = window.sessionStorage
break;
case 'local':
this.readStorage = window.localStorage
break;
default:
throwErrorMessage('当前配置的mode未再配置区内,可以检查传入配置。')
break;
}
this.config = config
}
Затем, поbootstrap
После инициализации некоторых текущих конфигураций вы можете передать текущий экземпляр на страницеcustomStorage
использовать некоторые функциональные методы.
import CustomStorage from 'web-storage-db'
const customStorage = new CustomStorage()
customStorage.bootStrap({
mode: 'local',
timeout: 3000,
})
export default customStorage
Сериализация JSON
дляWebStorage
С точки зрения хранения стоимости очень зависит отJSON的序列化
. Как показано ниже:
при сдаче на хранениеObject类型
, сохраненные данные становятся строкой своего типа, потому чтоWebStorage
Хранение может быть только字符串
существует в виде , поэтому, если мы хотим хранить данные ссылочного типа, нам нужно полагаться наJSON序列化
способность. пройти черезstringify
а такжеparse
После того, как некоторые методы обработают значение, вы можете очень хорошо хранить некоторые ссылочные типы.
Но есть некоторыеJSON.stringify
Данные недружественного типа, старайтесь не хранить, напримерundefined
, Function
, Symbol
Подождите, я также написал здесь простую функцию для проверки сохраненного значения.
/**
* 判断当前值是否能够呗JSON.stringify识别
* @param data 需要判断的值
* @returns 前参数是否可以string化
*/
export function hasStringify (data: any): boolean {
if (data === undefined) {
return false
}
if (data instanceof Function) {
return false
}
if (isSymbol(data)) {
return false
}
return true
}
вisSymbol
метод делаетSymbol
Типовое оценочное суждение.
/**
* 判断当前类型是否是Symbol
* @param val 需要判断的值
* @returns 当前参数是否是symbol
*/
export function isSymbol(val: any): boolean {
return typeof val === 'symbol'
}
сохранить данные
Если вам нужно сохранить данные вWebStorage
который сам обеспечиваетsetItem
API для этого здесьlocalStorage
Например, значение может быть сохранено в виде:
// # 原生
window.localStorage.setItem('key', 'value')
// # attribute形式存储
window.localStorage['key1'] = 'value'
window.localStorage.name = 'wangly19'
А мы в использовании, явно не будем пользоваться原生API
метод, большинство из них будет упаковано в工具方法
, чтобы справиться с некоторыми повторяющимися задачами. Например, в следующем пакете я сделал слой упаковки для содержимого хранимых данных и добавилJSON序列化数据
а также过期时间
.
/**
* 设置当前
* @param key 设置当前存储key
* @param value 设置当前存储value
*/
setItem(key: string, value) {
if (hasStringify(value)) {
const saveData: StorageSaveFormat = {
timestamp: new Date().getTime(),
data: value
}
console.log(saveData, 'saveData')
this.readStorage.setItem(key, JSON.stringify(saveData))
} else {
throwErrorMessage('需要存储的data不支持JSON.stringify方法,请检查当前数据')
}
}
// 使用
customStorage.setItem('setItem', [1])
читать данные
Раз есть задаток, значит и чтение должно быть, можно пройтиgetItem
илиObject
чтобы прочитать значение в виде . Теперь давайте рассмотрим три примера.
window.localStorage.setItem('person', JSON.stringify({
name: 'wangly19',
age: 22
}))
const person = window.localStorage.getItem('person')
JSON.parse(person)
// { name: "wangly19", age: 22 }
выше普通的使用方式
, в то время как мы封装
Когда сохраненные данные сохраняются, некоторые判断
, сделать сохраненные данные JSON解析化的处理
, вернуться напрямую解析后的数据
, более удобный и простой в использовании.
/**
* 获取数据
* @param key 获取当前数据key
* @returns 存储数据
*/
getItem<T = any>(key: string): T | null {
const content: StorageSaveFormat | null = JSON.parse(this.readStorage.getItem(key))
return content?.data || null
}
// # 使用
customStorage.getItem('setItem') // [1]
Удалить
Для удаления хранилища можно использовать не толькоremoveItem
,delete
и т. д. для выполнения операций над сохраненным значением移除
.
// # removeItem
window.localStorage.removeItem('person')
// # delete
delete window.localStorage.person
delete window.localStorage['peson']
Вы также можете использовать clear, чтобы очистить все данные в хранилище.
window.localStorage.clear()
Кроме того, если часть данных удаляетсяStorage
нет текущего хранилищаkey
данные, то нам не нужно выполнять текущий移除数据
операция. Давайте посмотрим на пакет нижеremoveItem
метод, я добавил слой值是否存在
чтобы решить, действительно ли необходимо выполнить этот шаг удаления.
/**
* 移除一条数据
* @param key 移除key
*/
removeItem(key: string) {
if (this.hasItem(key)) {
this.readStorage.removeItem(key)
}
}
/**
* 清除存储中所有数据
*/
clearAll() {
this.readStorage.clear()
}
длина
WebStorage
Принести свои собственныеlength
свойство, вы можете получить текущийStorage
длина.
window.localStorage.length
/**
* 返回当前存储库大小
* @returns number
*/
size(): number {
return this.readStorage.length
}
ключи и значения
Увидев это, многие друзья должны знать, как этого добиться? да, черезObject.keys
а такжеObject.values
можно получить текущийStorage
все вkey
а такжеvalue
. часть埋点SDK
будет сообщеноStorage
для фильтрации данных.
Object.keys(localStorage)
// (4) ["wwwPassLogout", "BIDUPSID", "BDSUGSTORED", "safeIconHis"]
Object.values(localStorage)
// (4) ["0", "30B3EE0AF6EE9F4F89EF16486C288502", "[{\"q\":\"localstorage%20%E8%BF%87%E6%9C%9F%E6%97%B6%…:\"new%20dateshijianchuo\",\"s\":4,\"t\":206989341223}]", ""]
Второй черезkey(index)
метод, вы можете напрямую получить значение определенной позиции.
window.localStorage.key(0)
window.localStorage.key(1)
window.localStorage.key(2)
существует工具类
Среди них я также провел封装
,можно использоватьgetKeys
, getValues
чтобы получить все пространство для храненияKey
а такжеValue
коллекция.
/**
* 获取所有key
* @returns 回storage当中所有key集合
*/
getKeys(): Array < string > {
return Object.keys(this.readStorage)
}
/**
* 获取所有value
* @returns 所有数据集合
*/
getValues() {
return Object.values(this.readStorage)
}
// # 使用
customStorage.getKeys()
customStorage.getValues()
Наличие собственности?
судить о текущемStorage
Наличие определенного атрибута вgetItem
Чтобы получить значение, а затем решить, существует ли значение, чтобы вынести суждение.
Но очевидно, что мы можем манипулировать Object какhasOwnProperty
метод, чтобы определить, существует ли это свойство в настоящее время.Поскольку возвращаемый тип является логическим, его относительно легче понять.
localStorage.key(2)
// "BDSUGSTORED"
localStorage.hasOwnProperty('BDSUGSTORED')
// true
localStorage.hasOwnProperty('1111')
// false
Исходя из этого, я также инкапсулировал метод оценки наличия значения в хранилище.hasItem
Способ сделать что-либоkey
Есть ли какое-то суждение в хранилище.
/**
* 判断是否存在该属性
* @param key 需要判断的key
*/
hasItem(key: string): boolean {
return this.readStorage.hasOwnProperty(key)
}
Расширенное использование
В расширенном использовании я представлю некоторые работы, которые могут быть碰到的问题
, и дайте немного解决方案
.
Срок действия
WebStorage
серединаSessionStorage
Цикл - текущая сессия. а такжеlocalStorage
Если не очистить вручную, сохраненные данные не будут активно очищаться.
Ключевые слова, которые зададут в интервью: Если localStorage активно не очищается, срок хранения хранимых данных не истечет.
Поэтому во многих случаях, если требуется время истечения, разработчику необходимо разобраться с этим самому, и метод обработки также очень прост и жесток.
Это займет время при передаче сохраненного значения. Обратитесь к приведенному ниже коду черезnew Date().getTime()
чтобы получить текущее время, а затем установить его в хранилище.
const person = {
// 存储数据
data: {
name: 'wangly19',
age: 22
},
// 过期时间
timestamp: new Date().getTime()
}
window.localStorage.setItem('person', JSON.stringify(person))
При получении времени будет простая суждение,当前时间 - 存储时间 >= 过期时间
Это может выполнить некоторую обработку суждения при управлении значением.
// # 原生
let person = localStorage.getItem('person')
person = JSON.parse(val)
// 这里可以使用一些库在做处理,如`dayjs`
if(new Date().getTime() - person.timestamp > [过期时间]) {
// 数据已经过期的一些操作
} else {
// 正常处理
}
Поэтому необходимоgetItem
метод, добавляю оценку времени истечения срока действия, и я также напрямую инкапсулирую эту логику в функцию.
/**
* 获取数据
* @param key 获取当前数据key
* @returns 存储数据
*/
getItem<T = any>(key: string): T | null {
const content: StorageSaveFormat | null = JSON.parse(this.readStorage.getItem(key))
if (content?.timestamp && new Date().getTime() - content.timestamp >= this.config.timeout) {
this.removeItem(key)
return null
}
return content?.data || null
}
функция слушателя
WebStorage
При изменении браузер будет запущенstorage
мероприятие.
А в приложении можно использоватьaddEventListener
добавить одинstorage
Событие обязывает его.
Спусковой механизм можно увидеть на рисунке ниже. в разных окнахstorage
При срабатывании выдает токevent
Информация. существуетevent
Среди них мы можем получить триггерurl
,新值
, 旧值
, 触发的key
В ожидании информации мы можем использовать этот API для мониторинга URL-адресов в браузере.
<script>
document.body.innerHTML = '初始化数据'
window.addEventListener("storage", function (event) {
const values = {
url: event.url,
key: event.key,
old: event.oldValue,
new: event.newValue,
}
document.body.innerHTML = JSON.stringify(values)
});
</script>
изменить данные
Так как нет родногоchangeItem
Это своего рода метод, поэтому нам нужно сделать некоторые методы самостоятельно封装
Для облегчения нашей частой необходимости модифицировать данные в хранилище.
Например, следующий, похожий наuseState
В форме обратного вызова для изменения значения.
changeItem('name', (oldValue) => {
const name = `update: ${oldValue} update`
return name
})
Метод реализации также относительно прост для понимания, благодаряgetItem
Чтобы получить данные, а затемsetItem
настраиватьonChange
Значение функции обратного вызова, которая объединяет согласованную операцию.
/**
* 修改当前存储内容数据
* @param key 当前存储key
* @param onChange 修改函数
* @param baseValue 基础数据
*/
changeItem<S = any>(
key: string,
onChange: (oldValue: S) => S | null, baseValue?: any
) {
const data = this.getItem<S>(key)
this.setItem(key, onChange(data || baseValue))
}
// # 使用
customStorage.changeItem('key', (oldValue) => {
retutn oldValue + 'newUpadte'
})
Пробел и переполнение
Если это активный пользователь, например, некоторые проекты по созданию документов, многие из них часто переходят кlocalStorage
В нем хранится очень много данных, и многие разработчики беспокоятся о том, будет ли он напрямую溢出
.
Так что здесь также предусмотрены некоторые решения для решения этих проблем.
Статус хранения и оценка хранилища
В безопасном контексте и поддерживаемом браузере черезStorageEstimate
Вы можете получить состояние кеша текущего браузера, например: сколько используется и сколько всего.
Следующий код сначала определяет, существует ли браузерnavigator
, а потом продолжайте судитьnavigator
Здесьstorage
, и, наконец, выполнитьestimate
Получить информацию о нашем магазине асинхронно.
if (navigator && navigator.storage) {
navigator.storage.estimate().then(estimate => {
console.log(estimate)
});
}
Этот веб-API требует, чтобы текущий проект находился под https. Полученная квота (общая память) составляет около 3 МБ, что, безусловно, является безопасным диапазоном памяти в сценариях разработки.
Очистка переполненного кэша
если в内存濒临溢出
В сценарии нам нужно освободить место для модификации данных после обработки.
Во-первых, мы собираем и сортируем данные по времени.Следующий метод заключается вstorage
все сtimestamp
Данные поля агрегируются и сортируются.
/**
* 获取当前清除存储空间,并且进行排序
*/
getClearStorage() {
const keys: string[] = Object.keys(this.readStorage)
const db: Array<{
key: string,
data: StorageSaveFormat
}> = []
keys.forEach(name => {
const item = this.getItem(name)
if (item.timestamp) {
db.push({
key: name,
data: item
})
}
})
return db.sort((a, b) => {
return a.data.timestamp - b.data.timestamp
})
}
Когда у вас есть отсортированный список данных, вам необходимо подумать об очистке данных и очистить более длительное время от текущего в соответствии с временной шкалой. В это время вам нужно понять условие:总大小(quota) - (使用大小)usage > [当前存入大小currentSize]
Когда у нас есть отсортированное хранилище, нам нужно только зациклиться, чтобы определить, соответствует ли текущее пространство требованиям, и, если да, выйти из цикла. Вместо этого продолжайте асинхронно, пока у нас не будет достаточно места.
initCacheSize просто сначала обновляет данные емкости. Получите новые данные о емкости.
/**
* 容量清理,直到满足存储大小为止
*/
detectionStorageContext(currentSize: number) {
if (this.usage + currentSize >= this.quota) {
const storage = this.getClearStorage()
for (let { key, data } of storage) {
// 如果满足要求就跳出,还不够就继续清除。
if (this.usage + currentSize < this.quota) break
// 刷新容量大小
this.removeItem(key)
initCacheSize()
}
}
}
Последний шаг -setItem
выполнить вdetectionStorageContext
, каждый раз, когда сохраненный контент обновляется, он будет оцениваться первым是否要溢出
, если бы добавленные или измененные данные переполнились бы, я бы сделал空间清理
.
Практическая сцена
В этой главе основное внимание уделяется некоторым простымWebStorage
сценарии использования.
история поиска
сюда, один из наших工具类
Он в основном сформирован. Наконец, вернемся к一开始的案例
, мы можем передатьchangItem
Быстро реализуйте эту функцию истории поиска, не беспокоясь о некоторых проблемах с совместимостью данных. Все, на чем нам нужно сосредоточиться, это настройка для сохранения значения.
Код дела выглядит следующим образом:
export default function Search() {
const [searchList, setSearchList] = useState([]);
useEffect(() => {
const data = localStore.getItem('search')
setSearchList(data || [])
}, [])
const onSearch = (value) => {
if (value) {
localStore.changeItem(
'search',
(oldValue) => {
if (oldValue.includes(value)) {
return oldValue;
}
if (oldValue) {
const newValue = [...oldValue, value];
setSearchList(newValue);
console.log(newValue, 'value');
return newValue;
}
if (value) {
setSearchList([value]);
return [value];
}
return [];
},
[],
);
}
};
return (
<div className="demo-app">
<Search
placeholder="请输入搜索内容"
enterButton="Search"
size="large"
suffix={suffix}
onSearch={onSearch}
/>
<div className="tag-wrapper">
{searchList.map((e) => {
return (
<Tag
key={e}
style={{
margin: 10,
}}
color="#108ee9"
>
{e}
</Tag>
);
})}
</div>
</div>
);
}
данные изображения
Браузер имеет ограничения на запросы, и большинство картинок в нашем проекте фактически возвращаются через back-end интерфейс.emoji
Эмодзи является примером.
Мы использовали данные эмодзи Zhihu для проведения моделирования и обнаружили, что всего существует 73 части данных.Очень неудобно запрашивать внутренние данные каждый раз при обновлении веб-страницы, и эти данные, очевидно, не нужно Хранится вStore
Среди них, в течение определенного периода времени, вероятность изменения очень маленькая, то мы помещаем его в本地存储
Очевидно, хороший выбор.
Когда страница загружается, я добавляю уровень суждения к запросу данных интерфейса, только数据为空
Только когда запрашивается список данных значка бэкэнда. Если это время истечения срока действия, данные локального значка будут очищены при получении данных, а затем данные внутреннего значка будут повторно запрошены, снова помещены в кеш, и будет обновлено новое время истечения срока действия.
const emojiRef = useRef(localStore.getItem('emoji'));
useEffect(() => {
if (!emojiRef.current) {
fetchEmojiIcon()
}
})
Если в вашем проекте много путей к ресурсам, вы можете поместить их вlocalStorage
Он хранится в нем для удобного использования при необходимости.
Ресурсы и материалы
- Когда браузер полностью отключает сторонние файлы cookie
- Сравнение и сводка нескольких методов хранения веб-данных localStorage, sessionStorage, cookie и session
- Что еще есть во внешнем хранилище, кроме localStorage?
- Web Storage (Second Edition)
- Боевой проект | Обработка кеша
Суммировать
Эта статья оWebStorage
Большинство навыков использования в этой книге сделали некоторые краткие сведения об использовании, инкапсулировали некоторые часто используемые операции и методы хранения, а также рассмотрели некоторые сложные сценарии, которые часто встречаются в работе, такие как время истечения срока действия, изменение данных, переполнение буфера и другие функции. Сделаны некоторые описания, и, наконец, он инкапсулирован в класс инструмента, который удобно использовать в повседневной разработке.
Наконец правильноWebStorage
После того, как у нас есть некоторое понимание, можем ли мы подумать о некоторых данных, которые можно рассматривать для хранения в последующей работе? При сохранении ресурсов он также может иметь лучшую производительность и облегчить давление на некоторых серверах.
последние хорошие статьи
- Я и Наггетс, через год после выпуска я подписал контракт с Наггетс | Середина 2021 года
- Обобщить практический опыт применения TypeScript в разработке проектов
концевые сноски
Если эта статья оказалась для вас полезной, я надеюсь, что вы поставите лайк и поддержите меня.
Эта статья была впервые опубликована в: Nuggets Technology Community
Тип: подписанная статья
Добавить Автора
Фаворит в колонке: javaScript базовый продвинутый
Публичный номер: Жизнь программы ItCodes