KV Storage — первый встроенный веб-модуль

Производители браузеров и эксперты по веб-производительности на протяжении большей части последнего десятилетия говорили, что localStorage работает медленно , и веб-разработчикам следует прекратить его использование.

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

Проблема в том, что API localStorage настолько заманчиво прост, и единственной асинхронной альтернативой localStorage является IndexedDB , которая (давайте посмотрим правде в глаза) не известна своей простотой использования или дружелюбным API.

Таким образом, разработчикам приходится выбирать между чем-то сложным в использовании и чем-то плохим для производительности. И хотя существуют библиотеки, которые предлагают простоту API localStorage , фактически используя API асинхронного хранилища, включение одной из этих библиотек в ваше приложение требует затрат на размер файла и может съедать ваш бюджет производительности .

Но что, если бы можно было получить производительность API асинхронного хранилища с простотой API localStorage без необходимости платить за размер файла?

Ну, скоро может быть. Chrome экспериментирует с новой функцией, известной как встроенные модули , и первой, которую мы планируем выпустить, является модуль асинхронного хранения ключей и значений под названием KV Storage .

Но прежде чем я углублюсь в подробности модуля KV Storage, позвольте мне объяснить, что я подразумеваю под встроенными модулями .

Что такое встроенные модули?

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

Как и традиционные веб-API, встроенные модули должны пройти процесс стандартизации — каждый из них будет иметь свою собственную спецификацию, которая требует проверки дизайна и положительных признаков поддержки как со стороны веб-разработчиков, так и со стороны других поставщиков браузеров, прежде чем он сможет быть выпущен. (В Chrome встроенные модули будут следовать тому же процессу запуска , который мы используем для реализации и поставки всех новых API.)

В отличие от традиционных веб-API, встроенные модули не доступны в глобальной области — они доступны только через импорт .

Отсутствие глобального доступа к встроенным модулям имеет множество преимуществ: они не добавят никаких дополнительных затрат на запуск нового контекста времени выполнения JavaScript (например, новой вкладки, рабочего или сервисного работника), а также не будут потреблять память или ЦП, если они на самом деле не импортированы. Более того, они не рискуют столкнуться с конфликтами имен с другими переменными, определенными в вашем коде.

Чтобы импортировать встроенный модуль, вы используете префикс std: за которым следует идентификатор встроенного модуля. Например, в поддерживаемых браузерах вы можете импортировать модуль KV Storage с помощью следующего кода (см. ниже , как использовать полифил KV Storage в неподдерживаемых браузерах ):

import storage, {StorageArea} from 'std:kv-storage';

Модуль KV Storage

Модуль KV Storage по своей простоте похож на localStorage API , но форма его API на самом деле ближе к Map JavaScript . Вместо getItem() , setItem() и removeItem() у него есть get() , set() и delete() . У него также есть другие методы, похожие на карту, недоступные для localStorage , такие keys() , values() и entries() , и, как и Map , его ключи не обязательно должны быть строками. Они могут быть любого структурированного сериализуемого типа .

В отличие от Map , все методы KV Storage возвращают либо промисы , либо асинхронные итераторы (поскольку основная суть этого модуля в том, что он не синхронен, в отличие от localStorage ). Чтобы подробно рассмотреть полный API, вы можете обратиться к спецификации .

Как вы, возможно, заметили из приведенного выше примера кода, модуль KV Storage имеет одно storage экспорта по умолчанию и одно с именем Export StorageArea .

storage — это экземпляр класса StorageArea с именем 'default' , и именно его разработчики чаще всего используют в коде своего приложения. Класс StorageArea предоставляется в случаях, когда необходима дополнительная изоляция (например, сторонняя библиотека, которая хранит данные и хочет избежать конфликтов с данными, хранящимися через экземпляр storage по умолчанию). Данные StorageArea хранятся в базе данных IndexedDB с именем kv-storage:${name} , где name — это имя экземпляра StorageArea .

Вот пример использования модуля KV Storage в вашем коде:

import storage from 'std:kv-storage';

const main = async () => {
  const oldPreferences = await storage.get('preferences');

  document.querySelector('form').addEventListener('submit', async () => {
    const newPreferences = Object.assign({}, oldPreferences, {
      // Updated preferences go here...
    });

    await storage.set('preferences', newPreferences);
  });
};

main();

Что делать, если браузер не поддерживает встроенный модуль?

Если вы знакомы с использованием собственных модулей JavaScript в браузерах, вы, вероятно, знаете, что (по крайней мере, до сих пор) импорт чего-либо, кроме URL-адреса, приведет к ошибке. И std:kv-storage не является допустимым URL-адресом.

Возникает вопрос: нужно ли нам ждать, пока все браузеры будут поддерживать встроенные модули, прежде чем мы сможем использовать их в нашем коде? К счастью, ответ — нет!

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

Импортировать карты

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

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

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

Вот как вы могли бы объявить карту импорта, чтобы это работало с модулем KV Storage:

<!-- The import map is inlined into your page -->
<script type="importmap">
{
  "imports": {
    "/path/to/kv-storage-polyfill.mjs": [
      "std:kv-storage",
      "/path/to/kv-storage-polyfill.mjs"
    ]
  }
}
</script>

<!-- Then any module scripts with import statements use the above map -->
<script type="module">
  import storage from '/path/to/kv-storage-polyfill.mjs';

  // Use `storage` ...
</script>

Ключевым моментом в приведенном выше коде является то, что URL-адрес /path/to/kv-storage-polyfill.mjs сопоставляется с двумя разными ресурсами: std:kv-storage , а затем снова исходный URL-адрес, /path/to/kv-storage-polyfill.mjs .

Поэтому, когда браузер встречает оператор импорта, ссылающийся на этот URL ( /path/to/kv-storage-polyfill.mjs ), он сначала пытается загрузить std:kv-storage , а если не может, то возвращается к загрузке. /path/to/kv-storage-polyfill.mjs .

Опять же, волшебство здесь в том, что браузеру не обязательно поддерживать карты импорта или встроенные модули, чтобы этот метод работал, поскольку URL-адрес, передаваемый в оператор импорта, является URL-адресом полифилла. Полифил на самом деле не является запасным вариантом, это значение по умолчанию. Встроенный модуль — это прогрессивное усовершенствование!

А как насчет браузеров, которые вообще не поддерживают модули?

Чтобы использовать карты импорта для условной загрузки встроенных модулей, вам нужно фактически использовать операторы import , что также означает, что вам нужно использовать скрипты модулей , то есть <script type="module"> .

В настоящее время более 80% браузеров поддерживают модули , а для браузеров, которые этого не делают, вы можете использовать метод модуль/номодуль для обслуживания устаревшего пакета. Обратите внимание: при создании сборки nomodule вам необходимо будет включить все полифилы, поскольку вы точно знаете, что браузеры, не поддерживающие модули, определенно не будут поддерживать встроенные модули.

Демонстрация хранилища KV

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

  • Браузеры, поддерживающие модули импорта карт и встроенный модуль, не загружают ненужный код.
  • Браузеры, которые поддерживают модули и импортируют карты, но не поддерживают встроенный модуль, загружают полифилл KV Storage (через загрузчик модулей браузера).
  • Браузеры, которые поддерживают модули, но не поддерживают карты импорта, также загружают полифилл KV Storage (через загрузчик модулей браузера).
  • Браузеры, которые вообще не поддерживают модули, получают полифилл KV Storage в своем устаревшем пакете (загружается через <script nomodule> ).

Демо-версия размещена на Glitch, поэтому вы можете просмотреть ее исходный код . У меня также есть подробное объяснение реализации в README . Не стесняйтесь взглянуть, если вам интересно узнать, как он устроен.

Чтобы увидеть собственный встроенный модуль в действии, вам необходимо загрузить демо-версию в Chrome 74 или более поздней версии с включенным флагом экспериментальных функций веб-платформы ( chrome://flags/#enable-experimental-web-platform-features ).

Вы можете убедиться, что встроенный модуль загружается, поскольку вы не увидите сценарий полифилла на панели исходного кода в DevTools; вместо этого вы увидите версию встроенного модуля (забавный факт: вы действительно можете проверить исходный код модуля или даже поставить в него точки останова!):

Исходный код модуля KV Storage в Chrome DevTools

Пожалуйста, дайте нам отзыв

Это введение должно было дать вам представление о возможностях встроенных модулей. И, надеюсь, вы в восторге! Нам бы очень хотелось, чтобы разработчики опробовали модуль KV Storage (а также все новые функции, обсуждаемые здесь) и оставили нам свои отзывы.

Вот ссылки GitHub, где вы можете оставить нам отзыв о каждой из функций, упомянутых в этой статье:

Если ваш сайт в настоящее время использует localStorage , вам следует попробовать переключиться на KV Storage API, чтобы проверить, отвечает ли он всем вашим потребностям. И если вы подпишетесь на пробную версию KV Storage origin , вы сможете развернуть эти функции уже сегодня. Все ваши пользователи получат выгоду от более высокой производительности хранилища, а пользователям Chrome 74+ не придется платить дополнительную плату за загрузку.