KV Storage - 웹 최초의 내장 모듈

지난 10년 동안 브라우저 공급업체와 웹 성능 전문가는 localStorage가 느리며 웹 개발자는 사용을 중단해야 한다고 말했습니다.

솔직히 말해서 사람들이 말하는 건 틀렸어. localStorage는 기본 스레드를 차단하는 동기 API이며 기본 스레드에 액세스할 때마다 페이지의 상호작용이 차단될 수 있습니다.

문제는 localStorage API가 매우 간단하며 localStorage의 유일한 비동기식 대안은 IndexedDB입니다. 이는 사용 편의성이나 편리한 API로 잘 알려져 있지 않습니다.

따라서 개발자는 사용하기 어려운 것과 성능이 나쁜 것 중에서 선택해야 합니다. 실제로 내부적으로 비동기 저장소 API를 사용하면서 localStorage API의 단순성을 제공하는 라이브러리가 있지만 앱에 이러한 라이브러리 중 하나를 포함하면 파일 크기 비용이 발생하므로 성능 예산을 소모할 수 있습니다.

하지만 파일 크기 비용을 지불하지 않고도 localStorage API의 단순성을 통해 비동기 저장소 API의 성능을 얻을 수 있다면 어떨까요?

음, 곧 있을 수도 있겠네요. Chrome은 내장 모듈이라는 새로운 기능을 실험하고 있으며 Google에서 제공할 첫 번째 기능은 KV Storage라는 비동기 키-값 스토리지 모듈입니다.

하지만 KV 스토리지 모듈에 관해 자세히 알아보기 전에 내장 모듈의 의미를 설명하겠습니다.

내장 모듈이란 무엇인가요?

기본 제공 모듈은 일반 자바스크립트 모듈과 유사하지만, 브라우저와 함께 제공되므로 다운로드할 필요가 없습니다.

기존 웹 API와 마찬가지로 내장 모듈은 표준화 프로세스를 거쳐야 합니다. 각 모듈은 출시 전에 디자인 검토 및 웹 개발자 및 다른 브라우저 공급업체의 지원에 대한 긍정적인 신호가 필요한 자체 사양을 갖습니다. (Chrome에서 기본 제공 모듈은 Google에서 모든 새 API를 구현하고 제공하는 데 사용하는 것과 동일한 시작 프로세스를 따릅니다.)

기존 웹 API와 달리 기본 제공 모듈은 전역 범위에 노출되지 않으며 가져오기를 통해서만 사용할 수 있습니다.

내장 모듈을 전역적으로 노출하지 않으면 많은 이점이 있습니다. 새 자바스크립트 런타임 컨텍스트 (예: 새 탭, 작업자 또는 서비스 워커)를 시작하는 데 오버헤드가 추가되지 않고 실제로 가져오지 않는 한 메모리나 CPU를 사용하지 않습니다. 또한 코드에 정의된 다른 변수와 이름이 충돌할 위험이 없습니다.

내장 모듈을 가져오려면 기본 제공 모듈의 식별자 앞에 std: 접두사를 사용합니다. 예를 들어 지원되는 브라우저에서 다음 코드를 사용하여 KV 저장소 모듈을 가져올 수 있습니다(지원되지 않는 브라우저에서 KV 저장소 폴리필을 사용하는 방법은 아래 참고).

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

KV 스토리지 모듈

KV 스토리지 모듈은 단순성에서 localStorage API와 비슷하지만 API 모양은 실제로 JavaScript Map에 더 가깝습니다. getItem(), setItem(), removeItem() 대신 get(), set(), delete()가 있습니다. 또한 keys(), values(), entries()와 같이 localStorage에서 사용할 수 없는 다른 맵과 유사한 메서드도 있으며 Map과 같이 키가 문자열일 필요가 없습니다. 구조화된 직렬화 가능한 유형이면 됩니다.

Map와 달리 모든 KV 저장소 메서드는 프로미스 또는 비동기 반복기를 반환합니다. 이 모듈의 요점은 localStorage와 달리 동기식이 아니기 때문입니다. 전체 API를 자세히 보려면 사양을 참고하세요.

위의 코드 예에서 확인할 수 있듯이 KV 스토리지 모듈에는 기본 내보내기 storage 하나와 내보내기 StorageArea라는 이름의 내보내기 하나가 있습니다.

storage는 이름이 'default'StorageArea 클래스의 인스턴스이며 개발자가 애플리케이션 코드에서 가장 자주 사용합니다. StorageArea 클래스는 추가 격리가 필요한 경우(예: 데이터를 저장하고 기본 storage 인스턴스를 통해 저장된 데이터와 충돌을 방지하려는 서드 파티 라이브러리)를 위해 제공됩니다. StorageArea 데이터는 이름이 kv-storage:${name}인 IndexedDB 데이터베이스에 저장됩니다. 여기서 name은 StorageArea 인스턴스의 이름입니다.

다음은 코드에서 KV 스토리지 모듈을 사용하는 방법의 예입니다.

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();

브라우저에서 내장 모듈을 지원하지 않으면 어떻게 되나요?

브라우저에서 네이티브 자바스크립트 모듈을 사용하는 데 익숙하다면 URL 이외의 항목을 가져오면 오류가 발생한다는 사실을 알 수 있습니다 (최소한까지). 또한 std:kv-storage은(는) 유효한 URL이 아닙니다.

그러면 이런 질문이 떠오를 수 있습니다. 모든 브라우저에서 기본 제공 모듈을 지원할 때까지 기다려야 코드에서 이 모듈을 사용할 수 있을까요? 다행히 답은 '아니요'입니다.

실험 중인 지도 가져오기라는 다른 기능의 도움 덕분에 한 브라우저에서라도 내장 모듈을 지원하는 즉시 내장 모듈을 사용할 수 있습니다.

지도 가져오기

가져오기 맵은 기본적으로 개발자가 하나 이상의 대체 식별자로 식별자를 별칭을 가져올 수 있는 메커니즘입니다.

이는 브라우저가 전체 애플리케이션에서 특정 가져오기 식별자를 확인하는 방식을 런타임에 변경할 수 있는 방법을 제공하므로 유용합니다.

내장 모듈의 경우 애플리케이션 코드에서 모듈의 polyfill을 참조할 수 있지만 내장 모듈을 지원하는 브라우저에서 그 버전을 로드할 수 있습니다.

다음은 가져오기 맵을 선언하여 KV 저장소 모듈에서 작동하게 하는 방법입니다.

<!-- 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)을 참조하는 import 문을 발견하면 먼저 std:kv-storage를 로드하려고 시도하고, 로드되지 않으면 /path/to/kv-storage-polyfill.mjs 로드로 대체합니다.

다시 말하지만 여기서 놀라운 점은 import 문에 전달되는 URL이 polyfill의 URL이므로 브라우저에서 이 기법이 작동하기 위해 가져오기 맵 또는 내장 모듈을 지원할 필요가 없다는 것입니다. polyfill은 실제로 대체가 아니며 기본값입니다. 기본 제공 모듈은 점진적으로 개선됩니다.

모듈을 전혀 지원하지 않는 브라우저는 어떻게 되나요?

가져오기 맵을 사용하여 기본 제공 모듈을 조건부로 로드하려면 실제로 import 문을 사용해야 합니다. 즉, 모듈 스크립트(예: <script type="module">)를 사용해야 합니다.

현재 브라우저의 80% 이상이 모듈을 지원하며 지원하지 않는 브라우저의 경우 module/nomodule 기법을 사용하여 기존 번들을 제공할 수 있습니다. nomodule 빌드를 생성할 때 모든 polyfill을 포함해야 합니다. 모듈을 지원하지 않는 브라우저는 내장 모듈을 지원하지 않을 것이기 때문입니다.

KV 스토리지 데모

이전 브라우저를 지원하면서 기본 제공 모듈을 사용할 수 있음을 보여주기 위해 위에서 설명한 모든 기술을 통합하고 현재 모든 브라우저에서 실행되는 데모를 준비했습니다.

  • 모듈, 지도 가져오기, 내장 모듈을 지원하는 브라우저는 불필요한 코드를 로드하지 않습니다.
  • 모듈을 지원하고 지도를 가져오지만 내장된 모듈을 지원하지 않는 브라우저는 브라우저의 모듈 로더를 통해 KV 저장소 polyfill을 로드합니다.
  • 모듈은 지원하지만 가져오기 맵은 지원하지 않는 브라우저에서도 브라우저의 모듈 로더를 통해 KV Storage 폴리필을 로드합니다.
  • 모듈을 전혀 지원하지 않는 브라우저는 기존 번들 (<script nomodule>를 통해 로드됨)에서 KV Storage 폴리필을 가져옵니다.

데모는 Glitch에서 호스팅되므로 소스를 확인할 수 있습니다. 구현에 관한 자세한 내용은 리드미에도 나와 있습니다. 어떻게 만들어졌는지 궁금하면 자유롭게 둘러보세요.

네이티브 내장 모듈이 실제로 작동하는 것을 보려면 실험용 웹 플랫폼 기능 플래그를 사용 설정(chrome://flags/#enable-experimental-web-platform-features)한 상태로 Chrome 74 이상에서 데모를 로드해야 합니다.

DevTools의 소스 패널에 polyfill 스크립트가 표시되지 않기 때문에 내장 모듈이 로드되고 있는지 확인할 수 있습니다. 대신 내장된 모듈 버전이 표시됩니다. 실제로 모듈의 소스 코드를 검사하거나 중단점을 배치할 수도 있습니다.

Chrome DevTools의 KV 저장소 모듈 소스

의견을 보내주세요.

이 소개를 통해 기본 제공 모듈로 가능한 작업을 알아봤습니다. 기대가 되시기를 바랍니다. 개발자 여러분께서는 KV 스토리지 모듈 (및 여기에서 설명하는 모든 새로운 기능)을 사용해 보시고 의견을 보내주세요.

다음은 이 문서에 언급된 각 기능에 관한 의견을 제공할 수 있는 GitHub 링크입니다.

사이트에서 현재 localStorage를 사용하고 있다면 KV Storage API로 전환하여 모든 요구사항을 충족하는지 확인해야 합니다. KV 스토리지 오리진 트라이얼에 가입하면 이러한 기능을 지금 바로 배포할 수 있습니다. 모든 사용자가 더 나은 저장소 성능의 혜택을 누릴 수 있으며 Chrome 74 이상 사용자는 추가 다운로드 비용을 지불하지 않아도 됩니다.