인덱스드 데이터베이스 API 3.0

W3C 작업 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2025/WD-IndexedDB-3-20250813/
최신 공개 버전:
https://www.w3.org/TR/IndexedDB/
편집자 초안:
https://w3c.github.io/IndexedDB/
이전 버전:
이력:
https://www.w3.org/standards/history/IndexedDB-3/
테스트 스위트:
https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
피드백:
GitHub
편집자:
(Microsoft)
이전 편집자:
Ali Alabbas (이전 Microsoft 소속)
Joshua Bell (이전 Google 소속)

초록

이 문서는 레코드 데이터베이스를 위한 API를 정의하며, 이 레코드는 단순 값과 계층적 객체를 보관합니다. 각 레코드는 키와 어떤 값으로 구성됩니다. 또한 데이터베이스는 저장하는 레코드에 대한 인덱스를 유지합니다. 애플리케이션 개발자는 API를 직접 사용하여 키 또는 인덱스를 사용해 레코드를 찾습니다. 쿼리 언어는 이 API 위에 계층화할 수 있습니다. 인덱스드 데이터베이스는 영구 B-트리 데이터 구조를 사용하여 구현할 수 있습니다.

이 문서의 상태

이 절에서는 이 문서가 발행된 시점의 상태를 설명합니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있습니다.

이 문서는 웹 애플리케이션 워킹 그룹이 권고안 트랙을 사용하여 작업 초안으로 발행했습니다. 작업 초안으로 발행되었다는 것은 W3C와 그 회원이 이를 지지한다는 의미가 아닙니다.

이 문서는 초안이며 언제든지 다른 문서에 의해 갱신되거나 대체되거나 폐기될 수 있습니다. 이 문서를 진행 중인 작업 이외의 것으로 인용하는 것은 적절하지 않습니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했습니다. W3C는 그룹의 결과물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있습니다. 자신이 알고 있는 특허에 필수 청구항이 포함되어 있다고 판단하는 사람은 W3C 특허 정책 제6절에 따라 해당 정보를 공개해야 합니다.

이 문서에는 2023년 11월 3일 W3C 프로세스 문서가 적용됩니다.

이 문서는 Indexed Database API의 제3판입니다. 단순히 "Indexed Database API"라는 제목의 제1판은 2015년 1월 8일에 W3C 권고안이 되었습니다. "Indexed Database API 2.0"이라는 제목의 제2판은 2018년 1월 30일에 W3C 권고안이 되었습니다.

Indexed Database API 3.0은 Indexed Database API 2.0을 대체하기 위한 것입니다.

1. 소개

사용자 에이전트는 웹 애플리케이션의 오프라인 데이터 요구 사항을 충족하기 위해 많은 수의 객체를 로컬에 저장해야 합니다. [WEBSTORAGE] 는 키와 그에 대응하는 값의 쌍을 저장하는 데 유용합니다. 그러나 키를 순서대로 검색하거나, 값을 효율적으로 검색하거나, 하나의 키에 대해 중복 값을 저장하는 기능은 제공하지 않습니다.

이 명세는 대부분의 정교한 쿼리 프로세서의 핵심인 고급 키-값 데이터 관리를 수행하기 위한 구체적인 API를 제공합니다. 이를 위해 트랜잭션 데이터베이스를 사용하여 키와 그에 대응하는 값(키당 하나 이상)을 저장하고, 키를 결정적인 순서로 순회할 수 있는 수단을 제공합니다. 이는 삽입과 삭제뿐만 아니라 매우 많은 수의 데이터 레코드를 순서대로 순회하는 데도 효율적인 것으로 여겨지는 영구 B-트리 데이터 구조를 사용하여 구현되는 경우가 많습니다.

다음 예에서는 API를 사용하여 "library" 데이터베이스에 접근합니다. 이 데이터베이스에는 "isbn" 속성을 기본 키로 사용하여 저장된 책 레코드를 보관하는 "books" 객체 저장소가 있습니다.

책 레코드에는 "title" 속성이 있습니다. 이 예에서는 인위적으로 책 제목이 고유해야 한다고 요구합니다. 코드는 unique 옵션을 설정하여 "by_title"이라는 인덱스를 생성함으로써 이를 강제합니다. 이 인덱스는 제목으로 책을 조회하는 데 사용되며, 고유하지 않은 제목을 가진 책이 추가되는 것을 방지합니다.

책 레코드에는 "author" 속성도 있으며, 이 속성은 고유할 필요가 없습니다. 코드는 이 속성으로 조회할 수 있도록 "by_author"라는 또 다른 인덱스를 생성합니다.

코드는 먼저 데이터베이스에 대한 연결을 엽니다. upgradeneeded 이벤트 핸들러 코드는 필요한 경우 객체 저장소와 인덱스를 생성합니다. success 이벤트 핸들러 코드는 이후 예에서 사용할 수 있도록 열린 연결을 저장합니다.

const request = indexedDB.open("library");
let db;

request.onupgradeneeded = function() {
  // 데이터베이스가 이전에 존재하지 않았으므로 객체 저장소와 인덱스를 생성합니다.
  const db = request.result;
  const store = db.createObjectStore("books", {keyPath: "isbn"});
  const titleIndex = store.createIndex("by_title", "title", {unique: true});
  const authorIndex = store.createIndex("by_author", "author");

  // 초기 데이터로 채웁니다.
  store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
  store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
  store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
};

request.onsuccess = function() {
  db = request.result;
};

다음 예에서는 트랜잭션을 사용하여 데이터베이스에 데이터를 채웁니다.

const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");

store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});

tx.oncomplete = function() {
  // 모든 요청이 성공했고 트랜잭션이 커밋되었습니다.
};

다음 예에서는 인덱스를 사용하여 데이터베이스에서 제목으로 하나의 책을 조회합니다.

const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_title");

const request = index.get("Bedrock Nights");
request.onsuccess = function() {
  const matching = request.result;
  if (matching !== undefined) {
    // 일치 항목을 찾았습니다.
    report(matching.isbn, matching.title, matching.author);
  } else {
    // 일치 항목을 찾지 못했습니다.
    report(null);
  }
};

다음 예에서는 인덱스와 커서를 사용하여 데이터베이스에서 저자로 모든 책을 조회합니다.

const tx = db.transaction("books", "readonly");
const store = tx.objectStore("books");
const index = store.index("by_author");

const request = index.openCursor(IDBKeyRange.only("Fred"));
request.onsuccess = function() {
  const cursor = request.result;
  if (cursor) {
    // 일치하는 각 레코드에 대해 호출됩니다.
    report(cursor.value.isbn, cursor.value.title, cursor.value.author);
    cursor.continue();
  } else {
    // 더 이상 일치하는 레코드가 없습니다.
    report(null);
  }
};

다음 예에서는 요청이 실패할 때 오류를 처리하는 한 가지 방법을 보여 줍니다.

const tx = db.transaction("books", "readwrite");
const store = tx.objectStore("books");
const request = store.put({title: "Water Buffaloes", author: "Slate", isbn: 987654});
request.onerror = function(event) {
  // "by_title" 인덱스의 고유성 제약 조건을 충족하지 못했습니다.
  report(request.error);
  // 트랜잭션이 중단되는 것을 방지하기 위해 event.preventDefault()를 호출할 수 있습니다.
};
tx.onabort = function() {
  // 그렇지 않으면 실패한 요청으로 인해 트랜잭션이 자동으로 중단됩니다.
  report(tx.error);
};

데이터베이스 연결은 더 이상 필요하지 않을 때 닫을 수 있습니다.

db.close();

나중에는 데이터베이스가 확장되어 다른 객체 저장소와 인덱스를 포함할 수 있습니다. 다음 예에서는 이전 버전에서 마이그레이션하는 한 가지 방법을 보여 줍니다.

const request = indexedDB.open("library", 3); // 버전 3을 요청합니다.
let db;

request.onupgradeneeded = function(event) {
  const db = request.result;
  if (event.oldVersion < 1) {
    // 버전 1은 데이터베이스의 첫 번째 버전입니다.
    const store = db.createObjectStore("books", {keyPath: "isbn"});
    const titleIndex = store.createIndex("by_title", "title", {unique: true});
    const authorIndex = store.createIndex("by_author", "author");
  }
  if (event.oldVersion < 2) {
    // 버전 2에서는 연도별 책의 새 인덱스가 도입됩니다.
    const bookStore = request.transaction.objectStore("books");
    const yearIndex = bookStore.createIndex("by_year", "year");
  }
  if (event.oldVersion < 3) {
    // 버전 3에서는 두 개의 인덱스가 있는 잡지용 새 객체 저장소가 도입됩니다.
    const magazines = db.createObjectStore("magazines");
    const publisherIndex = magazines.createIndex("by_publisher", "publisher");
    const frequencyIndex = magazines.createIndex("by_frequency", "frequency");
  }
};

request.onsuccess = function() {
  db = request.result; // db.version은 3이 됩니다.
};
하나의 데이터베이스는 여러 클라이언트(페이지와 워커)가 동시에 사용할 수 있으며 — 트랜잭션은 읽고 쓰는 동안 서로 충돌하지 않도록 보장합니다. 새 클라이언트가 데이터베이스를 업그레이드하려는 경우(upgradeneeded 이벤트를 통해), 다른 모든 클라이언트가 데이터베이스의 현재 버전에 대한 연결을 닫을 때까지 그렇게 할 수 없습니다.

새 클라이언트의 업그레이드가 차단되는 것을 방지하기 위해 클라이언트는 versionchange 이벤트를 수신할 수 있습니다. 이 이벤트는 다른 클라이언트가 데이터베이스를 업그레이드하려 할 때 발생합니다. 이 작업을 계속할 수 있도록 하려면 versionchange 이벤트에 반응하여 궁극적으로 이 클라이언트의 데이터베이스 연결을 닫는 작업을 수행합니다.

이를 수행하는 한 가지 방법은 페이지를 다시 로드하는 것입니다.

db.onversionchange = function() {
  // 먼저 저장되지 않은 데이터를 저장합니다.
  saveUnsavedData().then(function() {
    // 문서가 현재 사용 중이 아니라면 사용자의 상호작용 없이
    // 페이지를 다시 로드하는 것이 적절할 수 있습니다.
    if (!document.hasFocus()) {
      location.reload();
      // 다시 로드하면 데이터베이스가 닫히고 새 JavaScript
      // 및 데이터베이스 정의로 다시 로드됩니다.
    } else {
      // 문서에 포커스가 있으면 페이지를 다시 로드하는 것이 지나치게 방해가 될 수 있습니다.
      // 사용자에게 수동으로 수행하도록 요청할 수도 있습니다.
      displayMessage("최신 버전을 사용하려면 이 페이지를 다시 로드해 주세요.");
    }
  });
};

function saveUnsavedData() {
  // 이를 수행하는 방법은 앱에 따라 다릅니다.
}

function displayMessage() {
  // 사용자에게 비모달 메시지를 표시합니다.
}

또 다른 방법은 연결의 close() 메서드를 호출하는 것입니다. 그러나 이후 데이터베이스에 접근하려는 시도는 실패하므로 앱이 이를 인지하고 있는지 확인해야 합니다.

db.onversionchange = function() {
  saveUnsavedData().then(function() {
    db.close();
    stopUsingTheDatabase();
  });
};

function stopUsingTheDatabase() {
  // 앱을 더 이상 데이터베이스를 사용하지 않는 상태로 전환합니다.
}

새 클라이언트(업그레이드를 시도하는 클라이언트)는 blocked 이벤트를 사용하여 다른 클라이언트가 업그레이드가 수행되는 것을 방해하고 있는지 감지할 수 있습니다. blocked 이벤트는 다른 클라이언트의 versionchange 이벤트가 발생한 후에도 해당 클라이언트가 여전히 데이터베이스 연결을 유지하고 있으면 발생합니다.

const request = indexedDB.open("library", 4); // 버전 4를 요청합니다.
let blockedTimeout;

request.onblocked = function() {
  // 다른 클라이언트가 비동기적으로 데이터를 저장할 시간을 줍니다.
  blockedTimeout = setTimeout(function() {
    displayMessage("업그레이드가 차단되었습니다 - 이 사이트를 표시하는 다른 탭을 닫아 주세요.");
  }, 1000);
};

request.onupgradeneeded = function(event) {
  clearTimeout(blockedTimeout);
  hideMessage();
  // ...
};

function hideMessage() {
  // 이전에 표시된 메시지를 숨깁니다.
}

다른 클라이언트가 데이터베이스 연결을 끊지 못한 경우에만 사용자가 위 메시지를 보게 됩니다. 이상적으로는 사용자가 이 메시지를 전혀 보지 않아야 합니다.

2. 구성 요소

이름은 문자열이며 DOMString과 동등합니다. 즉, 빈 문자열을 포함하여 길이에 제한이 없는 임의의 16비트 코드 단위 시퀀스입니다. 이름은 항상 불투명한 16비트 코드 단위 시퀀스로 비교됩니다.

참고: 따라서 이름 비교는 대소문자의 차이뿐 아니라 정규화 형식, 제어 문자의 포함 또는 생략 및 Unicode 텍스트의 기타 차이와 같은 사소한 차이에도 민감합니다. [Charmod-Norm]

구현이 임의의 문자열을 지원하지 않는 저장 메커니즘을 사용하는 경우, 구현은 이스케이프 메커니즘 또는 이와 유사한 것을 사용하여 제공된 이름을 저장할 수 있는 문자열로 매핑할 수 있습니다.

목록 names에서 정렬된 이름 목록을 생성하려면 다음 단계를 실행합니다.

  1. sorted를 코드 단위 미만 알고리즘을 사용하여 오름차순으로 정렬된 names로 둡니다.

  2. sorted와 연결된 새로운 DOMStringList를 반환합니다.

세부 정보 이는 sort() 메서드를 Array (원소가 String인 배열)에 적용하는 것과 일치합니다. 이 순서는 각 문자열의 16비트 코드 단위를 비교하여 매우 효율적이고 일관되며 결정적인 정렬 순서를 생성합니다. 결과 목록은 특히 서로게이트 쌍으로 표현되는 코드 포인트의 경우 특정 알파벳 또는 사전식 순서와 일치하지 않습니다.

2.1. 데이터베이스

각 스토리지 키에는 연결된 데이터베이스 집합이 있습니다. 데이터베이스에는 0개 이상의 객체 저장소가 있으며, 이들은 데이터베이스에 저장된 데이터를 보관합니다.

데이터베이스에는 특정 스토리지 키 내에서 이를 식별하는 이름이 있습니다. 이 이름은 이름이며, 데이터베이스의 수명 동안 일정하게 유지됩니다.

데이터베이스에는 버전이 있습니다. 데이터베이스가 처음 생성되면 그 버전은 0(영)입니다.

참고: 각 데이터베이스에는 한 시점에 하나의 버전만 있으며, 데이터베이스는 동시에 여러 버전으로 존재할 수 없습니다. 버전을 변경하는 유일한 방법은 업그레이드 트랜잭션을 사용하는 것입니다.

데이터베이스에는 연결된 업그레이드 트랜잭션이 최대 하나 있으며, 이는 null 또는 업그레이드 트랜잭션이고, 초기값은 null입니다.

2.1.1. 데이터베이스 연결

스크립트는 데이터베이스와 직접 상호작용하지 않습니다. 대신, 스크립트는 연결을 통해 간접적으로 접근합니다. 연결 객체를 사용하여 해당 데이터베이스의 객체를 조작할 수 있습니다. 또한 해당 데이터베이스에 대한 트랜잭션을 얻는 유일한 방법이기도 합니다.

데이터베이스를 여는 동작은 연결을 생성합니다. 특정 데이터베이스에는 어느 시점이든 여러 연결이 존재할 수 있습니다.

연결은 해당 연결이 열린 전역 범위의 스토리지 키와 연결된 데이터베이스에만 접근할 수 있습니다.

참고: 이는 Document의 domain 변경의 영향을 받지 않습니다.

연결에는 버전이 있으며, 이는 연결이 생성될 때 설정됩니다. 업그레이드가 중단되지 않는 한 연결의 수명 동안 일정하게 유지되며, 업그레이드가 중단된 경우에는 데이터베이스의 이전 버전으로 설정됩니다. 연결이 닫힌 후에는 버전이 변경되지 않습니다.

각 연결에는 초기값이 false인 닫기 보류 플래그가 있습니다.

연결이 처음 생성되면 열린 상태입니다. 연결은 여러 방법을 통해 닫힐 수 있습니다. 연결이 생성된 실행 컨텍스트가 파괴되면(예: 사용자가 해당 페이지에서 다른 곳으로 이동한 경우) 연결이 닫힙니다. 또한 데이터베이스 연결 닫기 단계를 사용하여 연결을 명시적으로 닫을 수도 있습니다. 연결이 닫히면 아직 true로 설정되지 않은 경우 닫기 보류 플래그가 항상 true로 설정됩니다.

연결은 예외적인 상황에서 사용자 에이전트에 의해 닫힐 수 있습니다. 예를 들어 파일 시스템에 대한 접근 손실, 권한 변경 또는 스토리지 키의 스토리지 삭제 등이 있습니다. 이런 일이 발생하면 사용자 에이전트는 데이터베이스 연결 닫기를 연결 및 forced flag를 true로 설정하여 실행해야 합니다.

연결에는 객체 저장소 집합이 있으며, 연결이 생성될 때 연결된 데이터베이스의 객체 저장소 집합으로 초기화됩니다. 업그레이드 트랜잭션이 활성 상태인 경우를 제외하면 집합의 내용은 일정하게 유지됩니다.

연결의 부모 가져오기 알고리즘은 null을 반환합니다.

유형이 versionchange인 이벤트는 데이터베이스를 업그레이드하거나 삭제하려는 시도가 이루어지면 열린 연결에서 발생합니다. 이를 통해 연결은 업그레이드 또는 삭제가 진행될 수 있도록 닫힐 기회를 얻습니다.

유형이 close인 이벤트는 연결이 비정상적으로 닫히면 연결에서 발생합니다.

2.2. 객체 저장소

객체 저장소는 데이터베이스에 데이터를 저장하기 위한 주요 저장 메커니즘입니다.

각 데이터베이스에는 객체 저장소 집합이 있습니다. 객체 저장소 집합은 변경할 수 있지만, 업그레이드 트랜잭션을 사용할 때만, 즉 upgradeneeded 이벤트에 대한 응답으로만 변경할 수 있습니다. 새 데이터베이스가 생성될 때는 객체 저장소가 포함되어 있지 않습니다.

객체 저장소에는 객체 저장소에 저장된 데이터를 보관하는 레코드 목록이 있습니다. 각 레코드는 키와 값으로 구성됩니다. 목록은 키에 따라 오름차순으로 정렬됩니다. 특정 객체 저장소에는 같은 키를 가진 여러 레코드가 존재할 수 없습니다.

객체 저장소에는 이름인 이름이 있습니다. 어느 시점이든 이 이름은 해당 객체 저장소가 속한 데이터베이스 내에서 고유합니다.

객체 저장소에는 선택적으로 키 경로가 있습니다. 객체 저장소에 키 경로가 있으면 인라인 키를 사용한다고 합니다. 그렇지 않으면 아웃오브라인 키를 사용한다고 합니다.

객체 저장소에는 선택적으로 키 생성기가 있습니다.

객체 저장소는 다음 세 가지 소스 중 하나에서 레코드의 키를 얻을 수 있습니다.

  1. 키 생성기. 키가 필요할 때마다 키 생성기는 단조 증가하는 숫자를 생성합니다.

  2. 키 경로를 통해 키를 얻을 수 있습니다.

  3. 값이 객체 저장소에 저장될 때 키를 명시적으로 지정할 수도 있습니다.

2.2.1. 객체 저장소 핸들

스크립트는 객체 저장소와 직접 상호작용하지 않습니다. 대신, 트랜잭션 내에서 스크립트는 객체 저장소 핸들을 통해 간접적으로 접근합니다.

객체 저장소 핸들에는 연결된 객체 저장소와 연결된 트랜잭션이 있습니다. 여러 핸들이 서로 다른 트랜잭션에서 같은 객체 저장소와 연결될 수 있지만, 하나의 트랜잭션 내에서 특정 객체 저장소와 연결된 객체 저장소 핸들은 하나만 있어야 합니다.

객체 저장소 핸들에는 인덱스 집합이 있으며, 객체 저장소 핸들이 생성될 때 연결된 객체 저장소를 참조하는 인덱스 집합으로 초기화됩니다. 업그레이드 트랜잭션이 활성 상태인 경우를 제외하면 집합의 내용은 일정하게 유지됩니다.

객체 저장소 핸들에는 이름이 있으며, 객체 저장소 핸들이 생성될 때 연결된 객체 저장소의 이름으로 초기화됩니다. 업그레이드 트랜잭션이 활성 상태인 경우를 제외하면 이름은 일정하게 유지됩니다.

2.3. 값

각 레코드에는 값이 연결됩니다. 사용자 에이전트는 모든 직렬화 가능한 객체를 지원해야 합니다. 여기에는 String 원시 값 및 Date 객체와 같은 단순 유형뿐만 아니라 Object 및 Array 인스턴스, File 객체, Blob 객체, ImageData 객체 등이 포함됩니다. 레코드 값은 참조가 아니라 값으로 저장되고 검색되므로, 나중에 값이 변경되더라도 데이터베이스에 저장된 레코드에는 영향을 주지 않습니다.

레코드 값은 StructuredSerializeForStorage 연산이 출력한 Records입니다.

2.4. 키

인덱스드 데이터베이스에 저장된 레코드를 효율적으로 검색하기 위해, 각 레코드는 해당 키에 따라 구성됩니다.

키에는 다음 중 하나인 유형이 연결됩니다. 숫자, 날짜, 문자열, 바이너리, 또는 배열.

키에는 연결된 값도 있으며, 이는 유형이 숫자 또는 날짜인 경우 unrestricted double, 유형이 문자열인 경우 DOMString, 유형이 바이너리인 경우 바이트 시퀀스, 또는 유형이 배열인 경우 다른 키의 목록입니다.

ECMAScript [ECMA-262] 값은 값을 키로 변환하는 단계를 따라 키로 변환할 수 있습니다.

참고: 다음 ECMAScript 유형은 유효한 키입니다.

다른 ECMAScript 값을 키로 변환하려는 시도는 실패합니다.

배열 키는 키이며 유형이 배열입니다. 하위 키란 배열 키에 대해, 해당 배열 키의 값에 있는 항목입니다.

a와 b 두 키를 비교하려면 다음 단계를 실행합니다.

  1. ta를 a의 유형으로 둡니다.

  2. tb를 b의 유형으로 둡니다.

  3. ta가 tb와 같지 않으면 다음 단계를 실행합니다.

    1. ta가 배열이면 1을 반환합니다.

    2. tb가 배열이면 -1을 반환합니다.

    3. ta가 바이너리이면 1을 반환합니다.

    4. tb가 바이너리이면 -1을 반환합니다.

    5. ta가 문자열이면 1을 반환합니다.

    6. tb가 문자열이면 -1을 반환합니다.

    7. ta가 날짜이면 1을 반환합니다.

    8. 단언: tb는 날짜입니다.

    9. -1을 반환합니다.

  4. va를 a의 값으로 둡니다.

  5. vb를 b의 값으로 둡니다.

  6. ta에 따라 분기합니다.

    숫자
    날짜
    1. va가 vb보다 크면 1을 반환합니다.

    2. va가 vb보다 작으면 -1을 반환합니다.

    3. 0을 반환합니다.

    문자열
    1. va가 vb보다 코드 단위 기준으로 작으면 -1을 반환합니다.

    2. vb가 va보다 코드 단위 기준으로 작으면 1을 반환합니다.

    3. 0을 반환합니다.

    바이너리
    1. va가 vb보다 바이트 기준으로 작으면 -1을 반환합니다.

    2. vb가 va보다 바이트 기준으로 작으면 1을 반환합니다.

    3. 0을 반환합니다.

    배열
    1. length를 va의 크기와 vb의 크기 중 더 작은 값으로 둡니다.

    2. i를 0으로 둡니다.

    3. i가 length보다 작은 동안 다음을 수행합니다.

      1. c를 va[i]와 vb[i]를 사용해 재귀적으로 두 키를 비교한 결과로 둡니다.

      2. c가 0이 아니면 c를 반환합니다.

      3. i를 1 증가시킵니다.

    4. va의 크기가 vb의 크기보다 크면 1을 반환합니다.

    5. va의 크기가 vb의 크기보다 작으면 -1을 반환합니다.

    6. 0을 반환합니다.

키 a는 a와 b를 사용하여 두 키를 비교한 결과가 1이면 키 b보다 큽니다.

키 a는 a와 b를 사용하여 두 키를 비교한 결과가 -1이면 키 b보다 작습니다.

키 a는 a와 b를 사용하여 두 키를 비교한 결과가 0이면 키 b와 같습니다.

참고: 위 규칙의 결과로 음의 무한대가 키에 가능한 가장 작은 값입니다. 숫자 키는 날짜 키보다 작습니다. 날짜 키는 문자열 키보다 작습니다. 문자열 키는 바이너리 키보다 작습니다. 바이너리 키는 배열 키보다 작습니다. 가능한 가장 큰 키 값은 없습니다. 가능한 가장 큰 후보 키 뒤에 다른 키가 이어지는 배열은 그보다 더 크기 때문입니다.

참고: 바이너리 키의 구성원은 부호 있는 byte 값(-128 이상 127 이하)이 아니라 부호 없는 바이트 값 (0 이상 255 이하)으로 비교됩니다.

2.5. 키 경로

키 경로는 값에서 키를 추출하는 방법을 정의하는 문자열 또는 문자열 목록입니다. 유효한 키 경로는 다음 중 하나입니다.

참고: 키 경로 내에는 공백이 허용되지 않습니다.

키 경로 값은 StructuredSerializeForStorage에서 명시적으로 복사한 속성과 다음 유형별 속성에서만 접근할 수 있습니다.

유형 속성
Blob size, type
File name, lastModified
Array length
String length

2.6. 인덱스

객체 저장소에 있는 레코드를 해당 키 이외의 방법으로 검색하는 것이 유용할 때가 있습니다. 인덱스를 사용하면 객체 저장소 레코드의 값 속성을 사용하여 객체 저장소의 레코드를 조회할 수 있습니다.

인덱스는 특수한 영구 키-값 저장소이며 참조되는 객체 저장소가 있습니다. 인덱스에는 인덱스에 저장된 데이터를 보관하는 레코드 목록이 있습니다. 인덱스의 레코드는 참조되는 객체 저장소의 레코드가 삽입, 갱신 또는 삭제될 때마다 자동으로 채워집니다. 같은 객체 저장소를 참조하는 여러 인덱스가 있을 수 있으며, 이 경우 객체 저장소가 변경되면 그러한 모든 인덱스가 갱신됩니다.

인덱스 레코드의 값은 항상 인덱스의 참조되는 객체 저장소에 있는 키의 값입니다. 키는 참조되는 객체 저장소의 값에서 키 경로를 사용하여 얻습니다. 인덱스가 참조하는 객체 저장소의 키 X를 가진 특정 레코드가 값 A를 가지고, A에 대해 인덱스의 키 경로를 평가한 결과가 Y라면, 인덱스에는 키 Y와 값 X를 가진 레코드가 포함됩니다.

예를 들어 인덱스의 참조되는 객체 저장소에 키 123과 값 { name: "Alice", title: "CEO" }를 가진 레코드가 있고, 인덱스의 키 경로가 "name"이라면 인덱스에는 키 "Alice"와 값 123을 가진 레코드가 포함됩니다.

인덱스의 레코드에는 참조된 값이 있다고 합니다. 이는 인덱스의 참조되는 객체 저장소에서 키가 인덱스 레코드의 값과 같은 레코드의 값입니다. 따라서 위 예에서 인덱스 내 키가 Y이고 값이 X인 레코드는 A라는 참조된 값을 가집니다.

앞의 예에서 키가 "Alice"이고 값이 123인 인덱스 레코드는 { name: "Alice", title: "CEO" }라는 참조된 값을 가집니다.

참고: 인덱스의 각 레코드는 인덱스의 참조되는 객체 저장소에 있는 정확히 하나의 레코드만 참조합니다. 그러나 인덱스에는 객체 저장소의 같은 레코드를 참조하는 여러 레코드가 있을 수 있습니다. 또한 객체 저장소의 특정 레코드를 참조하는 인덱스 레코드가 하나도 없을 수도 있습니다.

인덱스의 레코드는 항상 레코드의 키에 따라 정렬됩니다. 그러나 객체 저장소와 달리 특정 인덱스에는 같은 키를 가진 여러 레코드가 포함될 수 있습니다. 이러한 레코드는 추가로 인덱스의 레코드 값 (즉, 참조되는 객체 저장소에 있는 레코드의 키)에 따라 정렬됩니다.

인덱스에는 이름인 이름이 있습니다. 어느 시점이든 이 이름은 인덱스의 참조되는 객체 저장소 내에서 고유합니다.

인덱스에는 고유 플래그가 있습니다. true이면 인덱스의 두 레코드가 같은 키를 갖지 못하도록 강제합니다. 인덱스의 참조되는 객체 저장소에 있는 레코드를 삽입하거나 수정하려 할 때, 레코드의 새 값에 대해 인덱스의 키 경로를 평가한 결과가 이미 인덱스에 존재한다면 객체 저장소에 대한 해당 수정 시도는 실패합니다.

인덱스에는 multiEntry 플래그가 있습니다. 이 플래그는 인덱스의 키 경로를 평가한 결과가 배열 키일 때 인덱스의 동작에 영향을 줍니다. multiEntry 플래그가 false이면 키가 배열 키인 하나의 레코드가 인덱스에 추가됩니다. multiEntry 플래그가 true이면 각 하위 키마다 하나의 레코드가 인덱스에 추가됩니다.

2.6.1. 인덱스 핸들

스크립트는 인덱스와 직접 상호작용하지 않습니다. 대신, 트랜잭션 내에서 스크립트는 인덱스 핸들을 통해 간접적으로 접근합니다.

인덱스 핸들에는 연결된 인덱스와 연결된 객체 저장소 핸들이 있습니다. 인덱스 핸들의 트랜잭션은 연결된 객체 저장소 핸들의 트랜잭션입니다. 여러 핸들이 서로 다른 트랜잭션에서 같은 인덱스와 연결될 수 있지만, 하나의 트랜잭션 내에서 특정 인덱스와 연결된 인덱스 핸들은 하나만 있어야 합니다.

인덱스 핸들에는 이름이 있으며, 이는 인덱스 핸들이 생성될 때 연결된 인덱스의 이름으로 초기화됩니다. 이름은 업그레이드 트랜잭션이 활성 상태인 경우를 제외하면 일정하게 유지됩니다.

2.7. 트랜잭션

트랜잭션은 데이터베이스의 데이터와 상호작용하는 데 사용됩니다. 데이터베이스에서 데이터를 읽거나 쓸 때마다 트랜잭션을 사용하여 수행합니다.

트랜잭션은 애플리케이션 및 시스템 장애로부터 어느 정도 보호를 제공합니다. 트랜잭션은 여러 데이터 레코드를 저장하거나 특정 데이터 레코드를 조건부로 수정하는 데 사용할 수 있습니다. 트랜잭션은 원자적이고 지속적인 데이터 접근 및 데이터 변경 작업 집합을 나타냅니다.

모든 트랜잭션은 연결을 통해 생성되며, 이 연결은 트랜잭션의 연결입니다.

트랜잭션에는 트랜잭션이 상호작용할 수 있는 객체 저장소의 집합인 범위가 있습니다.

참고: 트랜잭션의 범위는 트랜잭션이 업그레이드 트랜잭션인 경우를 제외하면 고정된 상태로 유지됩니다.

두 트랜잭션의 범위 모두에 어떤 객체 저장소가 포함되어 있으면 겹치는 범위를 가진다고 합니다.

트랜잭션에는 해당 트랜잭션에서 수행할 수 있는 상호작용의 유형을 결정하는 모드가 있습니다. 모드는 트랜잭션이 생성될 때 설정되며 트랜잭션의 수명 동안 고정된 상태로 유지됩니다. 트랜잭션의 모드는 다음 중 하나입니다.

"readonly"

트랜잭션은 데이터를 읽는 것만 허용됩니다. 이 유형의 트랜잭션에서는 수정할 수 없습니다. 이 방식의 장점은 여러 읽기 전용 트랜잭션의 범위가 겹치더라도, 즉 동일한 객체 저장소를 사용하더라도 동시에 시작할 수 있다는 것입니다. 이 유형의 트랜잭션은 데이터베이스가 열린 후에는 언제든지 생성할 수 있습니다.

"readwrite"

트랜잭션은 기존 객체 저장소의 데이터를 읽고, 수정하고, 삭제할 수 있습니다. 그러나 객체 저장소와 인덱스를 추가하거나 제거할 수는 없습니다. 여러 "readwrite" 트랜잭션은 그 범위가 겹치는 경우 동시에 시작할 수 없습니다. 그렇게 하면 트랜잭션이 진행되는 도중 서로의 데이터를 수정할 수 있기 때문입니다. 이 유형의 트랜잭션은 데이터베이스가 열린 후에는 언제든지 생성할 수 있습니다.

"versionchange"

트랜잭션은 기존 객체 저장소의 데이터를 읽고, 수정하고, 삭제할 수 있으며, 객체 저장소와 인덱스를 생성하고 제거할 수도 있습니다. 이를 수행할 수 있는 유일한 유형의 트랜잭션입니다. 이 유형의 트랜잭션은 수동으로 생성할 수 없으며, 대신 upgradeneeded 이벤트가 발생할 때 자동으로 생성됩니다.

트랜잭션에는 내구성 힌트가 있습니다. 이는 트랜잭션을 커밋할 때 성능 또는 내구성 중 무엇을 우선할지 사용자 에이전트에 알려 주는 힌트입니다. 내구성 힌트는 다음 중 하나입니다.

"strict"

사용자 에이전트는 보류 중인 모든 변경 사항이 영구 저장 매체에 성공적으로 기록되었음을 확인한 후에만 트랜잭션이 성공적으로 커밋되었다고 간주할 수 있습니다.

"relaxed"

사용자 에이전트는 보류 중인 모든 변경 사항이 운영 체제에 기록되는 즉시, 이후의 검증 없이 트랜잭션이 성공적으로 커밋되었다고 간주할 수 있습니다.

"default"

사용자 에이전트는 스토리지 버킷에 대한 기본 내구성 동작을 사용해야 합니다. 별도로 지정하지 않으면 트랜잭션의 기본값입니다.

참고: 일반적인 구현에서 "strict"는 complete 이벤트가 발생하기 전에 운영 체제의 모든 I/O 버퍼를 플러시하도록 사용자 에이전트에 지시하는 힌트입니다. 이렇게 하면 이후 운영 체제가 충돌하거나 전원이 끊겼을 때 변경 사항이 영구적으로 유지될 가능성에 대한 신뢰도가 높아지지만, 버퍼를 플러시하는 데 상당한 시간이 걸리고 휴대용 기기의 배터리 수명을 소모할 수 있습니다.

웹 애플리케이션은 캐시나 빠르게 변경되는 레코드와 같은 일시적 데이터에는 "relaxed"를 사용하고, 데이터 손실 위험 감소가 성능 및 전력에 미치는 영향보다 중요한 경우에는 "strict"를 사용하는 것이 권장됩니다. 구현은 애플리케이션이 제공한 내구성 힌트와 사용자 및 기기에 미치는 영향을 함께 고려하는 것이 권장됩니다.

트랜잭션에는 선택적으로 이벤트 루프인 정리 이벤트 루프가 있습니다.

트랜잭션에는 해당 트랜잭션에 대해 이루어진 보류 중인 요청의 요청 목록이 있습니다.

트랜잭션에는 트랜잭션이 중단된 경우 설정되는 오류가 있습니다.

참고: 구현자는 값 "null"이 abort()에서 설정되므로 오류로 간주된다는 점을 유의해야 합니다.

트랜잭션의 부모 가져오기 알고리즘은 트랜잭션의 연결을 반환합니다.

읽기 전용 트랜잭션은 모드가 "readonly"인 트랜잭션입니다.

읽기/쓰기 트랜잭션은 모드가 "readwrite"인 트랜잭션입니다.

2.7.1. 트랜잭션 수명 주기

트랜잭션에는 다음 중 하나인 상태가 있습니다.

활성

트랜잭션은 처음 생성되었을 때와, 해당 트랜잭션과 연결된 요청의 이벤트를 디스패치하는 동안 이 상태입니다.

트랜잭션이 이 상태일 때는 새 요청을 해당 트랜잭션에 대해 할 수 있습니다.

비활성

트랜잭션은 생성 후 제어가 이벤트 루프로 반환된 뒤와 이벤트가 디스패치되지 않는 동안 이 상태입니다.

트랜잭션이 이 상태일 때는 해당 트랜잭션에 대해 요청을 할 수 없습니다.

커밋 중

트랜잭션과 연결된 모든 요청이 완료되면, 트랜잭션은 커밋을 시도하면서 이 상태로 들어갑니다.

트랜잭션이 이 상태일 때는 해당 트랜잭션에 대해 요청을 할 수 없습니다.

완료

트랜잭션이 커밋되거나 중단되면 이 상태로 들어갑니다.

트랜잭션이 이 상태일 때는 해당 트랜잭션에 대해 요청을 할 수 없습니다.

트랜잭션은 짧은 수명을 가지는 것이 기대됩니다. 이는 아래에 설명된 자동 커밋 기능을 통해 장려됩니다.

참고: 작성자는 여전히 트랜잭션을 오랫동안 활성 상태로 유지할 수 있지만, 이러한 사용 패턴은 좋지 않은 사용자 경험으로 이어질 수 있으므로 권장되지 않습니다.

트랜잭션의 수명은 다음과 같습니다.

  1. 트랜잭션은 범위와 모드를 가지고 생성됩니다. 트랜잭션이 생성되면 그 상태는 처음에 활성입니다.

  2. 구현이 아래에 정의된 트랜잭션의 범위와 모드에 대한 제약 조건을 적용할 수 있게 되면, 구현은 트랜잭션을 비동기적으로 시작하기 위한 데이터베이스 태스크를 큐에 추가해야 합니다.

    트랜잭션이 시작되면 구현은 트랜잭션에 대해 배치된 요청을 실행하기 시작할 수 있습니다. 요청은 해당 트랜잭션에 대해 이루어진 순서대로 실행되어야 합니다. 마찬가지로 그 결과도 특정 트랜잭션에 요청이 배치된 순서대로 반환되어야 합니다. 서로 다른 트랜잭션의 요청 결과가 반환되는 순서에 대해서는 보장하지 않습니다.

    참고: 트랜잭션 모드는 서로 다른 트랜잭션에 배치된 두 요청이 데이터베이스에 최종적으로 저장되는 데이터에 영향을 주지 않고 어떤 순서로든 실행될 수 있도록 보장합니다.

  3. 트랜잭션과 연결된 각 요청이 처리되면, success 또는 error 이벤트가 발생합니다. 이벤트가 디스패치되는 동안 트랜잭션의 상태는 활성으로 설정되어 트랜잭션에 대해 추가 요청을 할 수 있습니다. 이벤트 디스패치가 완료되면 트랜잭션의 상태는 다시 비활성으로 설정됩니다.

  4. 트랜잭션은 완료되기 전이라면 언제든지 중단할 수 있으며, 현재 활성 상태가 아니거나 아직 시작되지 않았더라도 마찬가지입니다.

    abort()를 명시적으로 호출하면 중단이 시작됩니다. 또한 스크립트에서 처리하지 않은 실패한 요청 이후에도 중단이 시작됩니다.

    트랜잭션이 중단되면 구현은 해당 트랜잭션 동안 데이터베이스에 이루어진 모든 변경 사항을 되돌려야 합니다. 여기에는 객체 저장소의 내용 변경뿐 아니라 객체 저장소 및 인덱스의 추가와 제거도 포함됩니다.

  5. 트랜잭션에 배치된 모든 요청이 완료되고 반환된 결과가 처리되었으며, 새 요청이 트랜잭션에 배치되지 않았고 트랜잭션이 중단되지 않았다면, 구현은 비활성 트랜잭션을 커밋하려고 시도해야 합니다.

    commit()을 명시적으로 호출하면 요청 결과가 스크립트에서 처리되기를 기다리지 않고 커밋을 시작합니다.

    커밋하는 동안 트랜잭션의 상태는 커밋 중으로 설정됩니다. 구현은 트랜잭션에 배치된 요청에 의해 데이터베이스에 이루어진 모든 변경 사항을 원자적으로 기록해야 합니다. 즉, 모든 변경 사항을 기록하거나, 디스크 쓰기 오류와 같은 오류가 발생한 경우에는 어떤 변경 사항도 데이터베이스에 기록하지 않아야 하며 트랜잭션 중단 단계를 따라야 합니다.

  6. 트랜잭션이 커밋되거나 중단되면, 그 상태는 완료로 설정됩니다.

구현은 트랜잭션이 활성일 때마다 해당 트랜잭션에 요청을 배치할 수 있도록 해야 합니다. 이는 트랜잭션이 아직 시작되지 않은 경우에도 마찬가지입니다. 트랜잭션이 시작되기 전까지 구현은 이러한 요청을 실행해서는 안 되지만, 요청과 그 순서를 추적해야 합니다.

트랜잭션은 생성된 시점부터 그 상태가 완료로 설정될 때까지 활성 상태라고 합니다.

Indexed Database 트랜잭션을 정리하려면 다음 단계를 실행합니다. 트랜잭션이 하나라도 정리되었으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

  1. 현재 이벤트 루프와 일치하는 정리 이벤트 루프를 가진 트랜잭션이 없다면 false를 반환합니다.

  2. 현재 이벤트 루프와 일치하는 정리 이벤트 루프를 가진 각 트랜잭션 transaction에 대해 다음을 수행합니다.

    1. transaction의 상태를 비활성으로 설정합니다.

    2. transaction의 정리 이벤트 루프를 지웁니다.

  3. true를 반환합니다.

참고: 이 단계들은 [HTML]에서 호출됩니다. 이 단계들은 transaction()에 대한 스크립트 호출로 생성된 트랜잭션이 스크립트를 호출한 태스크가 완료된 후 비활성화되도록 보장합니다. 이 단계들은 각 트랜잭션에 대해 최대 한 번 실행됩니다.

유형이 complete인 이벤트는 성공적으로 커밋된 트랜잭션에서 발생합니다.

유형이 abort인 이벤트는 중단된 트랜잭션에서 발생합니다.

2.7.2. 트랜잭션 스케줄링

다음 제약 조건은 트랜잭션을 언제 시작할 수 있는지를 정의합니다.

구현은 추가적인 제약 조건을 부과할 수 있습니다. 예를 들어 구현은 겹치지 않는 읽기/쓰기 트랜잭션을 병렬로 시작할 필요가 없으며, 시작된 트랜잭션 수에 제한을 둘 수도 있습니다.

참고: 이러한 제약 조건은 다음을 의미합니다.

2.7.3. 업그레이드 트랜잭션

업그레이드 트랜잭션은 트랜잭션이며 그 모드는 "versionchange"입니다.

연결이 데이터베이스에 열린 후 현재 버전보다 큰 버전이 지정되면, 데이터베이스를 업그레이드하는 단계를 실행할 때 업그레이드 트랜잭션이 자동으로 생성됩니다. 이 트랜잭션은 upgradeneeded 이벤트 핸들러 내부에서 활성 상태가 됩니다.

참고: 업그레이드 트랜잭션을 사용하면 데이터베이스에서 객체 저장소와 인덱스를 생성하고, 이름을 바꾸고, 삭제할 수 있습니다.

업그레이드 트랜잭션은 배타적입니다. 데이터베이스 연결 열기 단계는 업그레이드 트랜잭션이 활성 상태일 때 데이터베이스에 대한 연결이 하나만 열려 있도록 보장합니다. 같은 데이터베이스에 대한 다른 모든 연결이 닫힐 때까지 upgradeneeded 이벤트는 발생하지 않으며, 따라서 업그레이드 트랜잭션도 시작되지 않습니다. 이를 통해 모든 이전 트랜잭션이 완료되도록 보장합니다.

업그레이드 트랜잭션이 활성 상태인 동안에는 같은 데이터베이스에 추가 연결을 열려는 시도가 지연되며, 같은 연결을 사용하여 transaction()을 호출해 추가 트랜잭션을 시작하려는 모든 시도는 예외를 발생시킵니다. 이를 통해 다른 트랜잭션이 동시에 활성 상태가 되지 않도록 보장하고, 업그레이드 트랜잭션이 활성 상태인 동안 같은 데이터베이스에 대해 새 트랜잭션이 큐에 추가되지 않도록 보장합니다.

또한 이를 통해 업그레이드 트랜잭션이 완료되면 데이터베이스의 객체 저장소와 인덱스 집합이 이후 모든 연결과 트랜잭션의 수명 동안 일정하게 유지되도록 보장합니다.

2.8. 요청

데이터베이스에 대한 각 비동기 작업은 요청을 사용하여 수행됩니다. 모든 요청은 하나의 작업을 나타냅니다.

요청에는 초기값이 false인 처리됨 플래그가 있습니다. 요청과 연결된 작업이 실행되면 이 플래그는 true로 설정됩니다.

요청의 처리됨 플래그가 true이면 그 요청은 처리됨 상태라고 합니다.

요청에는 초기값이 false인 완료 플래그가 있습니다. 요청과 연결된 작업의 결과를 사용할 수 있게 되면 이 플래그는 true로 설정됩니다.

요청에는 소스 객체가 있습니다.

요청에는 결과와 오류가 있으며, 둘 다 완료 플래그가 true가 되기 전에는 접근할 수 없습니다.

요청에는 초기값이 null인 트랜잭션이 있습니다. 이는 요청을 비동기적으로 실행하는 단계를 사용하여 요청이 트랜잭션에 대해 배치될 때 설정됩니다.

요청이 이루어지면 요청의 완료 플래그가 false로 설정된 새 요청이 반환됩니다. 요청이 성공적으로 완료되면 완료 플래그는 true로 설정되고, 결과는 요청의 결과로 설정되며, 유형이 success인 이벤트가 요청에서 발생합니다.

작업을 수행하는 동안 오류가 발생하면 요청의 완료 플래그가 true로 설정되고, 요청의 오류는 해당 오류로 설정되며, 유형이 error인 이벤트가 요청에서 발생합니다.

요청의 부모 가져오기 알고리즘은 요청의 트랜잭션을 반환합니다.

참고: 요청은 일반적으로 재사용되지 않지만 예외가 있습니다. 커서를 반복할 때 반복 성공 여부는 커서를 여는 데 사용한 것과 동일한 요청 객체에 보고됩니다. 또한 업그레이드 트랜잭션이 필요한 경우, 동일한 열기 요청이 upgradeneeded 이벤트와 열기 작업 자체의 최종 결과 모두에 사용됩니다. 일부 경우에는 요청의 완료 플래그가 false로 설정된 후 다시 true로 설정될 수 있으며, 결과가 바뀌거나 대신 오류가 설정될 수 있습니다.

2.8.1. 열기 요청

열기 요청은 연결을 열거나 데이터베이스를 삭제할 때 사용하는 특별한 유형의 요청입니다. success 및 error 이벤트 외에도 진행 상황을 나타내기 위해 blocked 및 upgradeneeded 이벤트가 열기 요청에서 발생할 수 있습니다.

열기 요청의 소스는 항상 null입니다.

열기 요청의 트랜잭션은 upgradeneeded 이벤트가 발생하지 않은 경우 null입니다.

열기 요청의 부모 가져오기 알고리즘은 null을 반환합니다.

2.8.2. 연결 큐

열기 요청은 연결 큐에서 처리됩니다. 큐에는 스토리지 키와 이름에 연결된 모든 열기 요청이 포함됩니다. 연결 큐에 추가된 요청은 순서대로 처리되며, 각 요청은 다음 요청이 처리되기 전에 끝까지 실행되어야 합니다. 열기 요청은 다른 연결에 의해 차단될 수 있으며, 이 경우 요청이 완료되어 이후 요청을 처리할 수 있도록 해당 연결들이 닫혀야 합니다.

참고: 연결 큐는 특정 브라우징 컨텍스트 외부에서 요청이 처리되므로 이벤트 루프와 연결된 태스크 큐가 아닙니다. 완료된 열기 요청에 대한 이벤트 전달은 여전히 요청이 이루어진 컨텍스트의 이벤트 루프와 연결된 태스크 큐를 거칩니다.

2.9. 키 범위

키 또는 키 범위를 사용하여 객체 저장소와 인덱스에서 레코드를 검색할 수 있습니다. 키 범위는 키에 사용되는 어떤 데이터 유형의 연속적인 구간입니다.

키 범위에는 연결된 하한이 있으며, null 또는 키입니다.

키 범위에는 연결된 상한이 있으며, null 또는 키입니다.

키 범위에는 연결된 하한 개방 플래그가 있습니다. 달리 명시하지 않으면 false입니다.

키 범위에는 연결된 상한 개방 플래그가 있습니다. 달리 명시하지 않으면 false입니다.

키 범위의 하한은 상한과 같을 수 있습니다. 키 범위의 하한은 상한보다 커서는 안 됩니다.

key만 포함하는 키 범위는 하한과 상한이 모두 key와 같습니다.

다음 두 조건이 모두 충족되면 key는 range라는 키 범위 안에 있습니다.

참고:

제한 없는 키 범위는 키 범위이며 하한과 상한이 모두 null입니다. 모든 키는 제한 없는 키 범위 안에 있습니다.

value와 선택적 null disallowed flag를 사용하여 값을 키 범위로 변환하려면 다음 단계를 실행합니다.

  1. value가 키 범위이면 value를 반환합니다.

  2. value가 undefined 또는 null이면, null disallowed flag가 true인 경우 "DataError" DOMException을 던지고, 그렇지 않으면 제한 없는 키 범위를 반환합니다.

  3. key를 value를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  4. key가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  5. key만 포함하는 키 범위를 반환합니다.

잠재적으로 유효한 키 범위는 키 범위로 변환 가능한 유형을 가진 ECMAScript 값입니다. 특정 값이 실제로 키 범위로 성공적으로 변환되는지, 즉 해당 값을 사용해 값을 키 범위로 변환할 때 예외가 발생하는지는 관련이 없습니다.

참고: 예를 들어 분리된 BufferSource는 잠재적으로 유효한 키 범위이지만 값을 키 범위로 변환할 때 사용하면 예외가 발생합니다.

ECMAScript value를 사용하여 값이 잠재적으로 유효한 키 범위인지 판별하려면 다음 단계를 실행합니다.

  1. value가 키 범위이면 true를 반환합니다.

  2. key를 value를 사용하여 값을 키로 변환한 결과로 둡니다.

  3. key가 "invalid type"이면 false를 반환합니다.

  4. 그렇지 않으면 true를 반환합니다.

참고: getAll() 및 getAllKeys() 메서드는 첫 번째 인수를 처리하기 위해 잠재적으로 유효한 키 범위인지를 사용합니다. 인수가 잠재적으로 유효한 키 범위이면 getAll() 및 getAllKeys()은 해당 인수를 사용하여 값을 키 범위로 변환합니다. 그렇지 않으면 첫 번째 인수에 IDBGetAllOptions가 사용됩니다.

getAll() 및 getAllKeys()은 값을 키로 변환할 때 "invalid value"를 반환하는 Date, Array, 및 ArrayBuffer 첫 번째 인수에 대해 예외를 던집니다. 예를 들어 첫 번째 인수로 NaN Date를 사용하여 getAll()을 실행하면 기본값을 가진 IDBGetAllOptions 사전을 성공적으로 사용하는 대신 예외를 던집니다.

2.10. 커서

커서는 특정 방향으로 인덱스 또는 객체 저장소의 레코드 범위를 반복하는 데 사용됩니다.

커서에는 커서를 연 인덱스 핸들 또는 객체 저장소 핸들인 소스 핸들이 있습니다.

커서에는 커서의 소스 핸들의 트랜잭션인 트랜잭션이 있습니다.

커서에는 인덱스 또는 객체 저장소에 있는 레코드의 범위가 있습니다.

커서에는 커서의 소스 핸들에서 가져온 인덱스 또는 객체 저장소인 소스가 있습니다. 커서의 소스는 커서가 반복 중인 레코드와 어떤 인덱스 또는 객체 저장소가 연결되는지를 나타냅니다. 커서의 소스 핸들이 인덱스 핸들이면, 커서의 소스는 인덱스 핸들과 연결된 인덱스입니다. 그렇지 않으면 커서의 소스는 객체 저장소 핸들과 연결된 객체 저장소입니다.

커서에는 반복할 때 레코드 키의 단조 증가 또는 단조 감소 순서 중 어느 방향으로 이동하는지와 인덱스를 반복할 때 중복 값을 건너뛰는지를 결정하는 방향이 있습니다. 커서의 방향은 커서의 초기 위치가 소스의 시작인지 끝인지도 결정합니다. 커서의 방향은 다음 중 하나입니다.

"next"

이 방향은 커서가 소스의 시작에서 열리게 합니다. 반복할 때 커서는 중복을 포함한 모든 레코드를 키의 단조 증가 순서로 산출해야 합니다.

"nextunique"

이 방향은 커서가 소스의 시작에서 열리게 합니다. 반복할 때 커서는 같은 키를 가진 레코드를 산출하지 않아야 하지만, 그 외의 모든 레코드는 키의 단조 증가 순서로 산출해야 합니다. 중복 값을 가진 각 키에서는 첫 번째 레코드만 산출됩니다. 소스가 객체 저장소이거나 인덱스의 고유 플래그가 true로 설정되어 있으면 이 방향은 "next"와 정확히 같은 동작을 합니다.

"prev"

이 방향은 커서가 소스의 끝에서 열리게 합니다. 반복할 때 커서는 중복을 포함한 모든 레코드를 키의 단조 감소 순서로 산출해야 합니다.

"prevunique"

이 방향은 커서가 소스의 끝에서 열리게 합니다. 반복할 때 커서는 같은 키를 가진 레코드를 산출하지 않아야 하지만, 그 외의 모든 레코드는 키의 단조 감소 순서로 산출해야 합니다. 중복 값을 가진 각 키에서는 첫 번째 레코드만 산출됩니다. 소스가 객체 저장소이거나 인덱스의 고유 플래그가 true로 설정되어 있으면 이 방향은 "prev"와 정확히 같은 동작을 합니다.

커서에는 그 범위 내의 위치가 있습니다. 커서가 반복하는 레코드 목록은 커서의 전체 범위를 반복하기 전에 변경될 수 있습니다. 이를 처리하기 위해 커서는 위치를 인덱스로 유지하는 대신 이전에 반환한 레코드의 키로 유지합니다. 정방향으로 반복하는 커서가 다음 레코드로 이동하도록 다시 요청받으면, 이전에 반환한 것보다 큰 키 중 가장 작은 키를 가진 레코드를 반환합니다. 역방향으로 반복하는 커서의 경우 반대이며, 이전에 반환한 것보다 작은 키 중 가장 큰 키를 가진 레코드를 반환합니다.

인덱스를 반복하는 커서의 경우에는 여러 레코드가 같은 키를 가질 수 있고 따라서 값에 따라서도 정렬되므로 상황이 조금 더 복잡합니다. 인덱스를 반복할 때 커서에는 인덱스에서 이전에 찾은 레코드의 값을 나타내는 객체 저장소 위치도 있습니다. 다음 적절한 레코드를 찾을 때 위치와 객체 저장소 위치가 모두 사용됩니다.

커서에는 마지막으로 반복된 레코드의 키와 값을 나타내는 키와 값이 있습니다.

커서에는 값 획득 플래그가 있습니다. 이 플래그가 false이면 커서는 다음 값을 로드하는 중이거나 범위의 끝에 도달한 상태입니다. true이면 커서가 현재 값을 보유하고 있으며 다음 값으로 반복할 준비가 되었음을 나타냅니다.

커서의 소스가 객체 저장소이면, 커서의 유효 객체 저장소는 그 객체 저장소이고, 커서의 유효 키는 커서의 위치입니다. 커서의 소스가 인덱스이면, 커서의 유효 객체 저장소는 해당 인덱스의 참조되는 객체 저장소이고, 유효 키는 커서의 객체 저장소 위치입니다.

커서에는 커서를 여는 데 사용된 요청인 요청이 있습니다.

커서에는 또한 커서의 값이 API를 통해 노출되는지를 나타내는 키 전용 플래그가 있습니다.

2.11. 키 생성기

객체 저장소를 생성할 때 키 생성기를 사용하도록 지정할 수 있습니다. 키 생성기는 별도로 지정하지 않은 경우 객체 저장소에 삽입되는 레코드의 키를 생성하는 데 사용됩니다.

키 생성기에는 현재 번호가 있습니다. 현재 번호는 항상 253 (9007199254740992) + 1 이하인 양의 정수입니다. 키 생성기의 현재 번호의 초기값은 1이며, 연결된 객체 저장소가 생성될 때 설정됩니다. 현재 번호는 키가 생성될 때마다 증가하며, 명시적 키를 사용하여 특정 값으로 갱신될 수 있습니다.

참고: 키 생성기를 사용하는 각 객체 저장소는 별도의 생성기를 사용합니다. 즉, 한 객체 저장소와 상호작용해도 다른 객체 저장소의 키 생성기에는 영향을 주지 않습니다.

키 생성기의 현재 번호를 수정하는 것은 데이터베이스 작업의 일부로 간주됩니다. 즉, 작업이 실패하여 작업이 되돌려지면 현재 번호도 작업이 시작되기 전의 값으로 되돌려집니다. 이는 키 생성기가 사용될 때 현재 번호가 1 증가하여 발생하는 변경과, 레코드를 저장하는 호출에서 키 값을 지정하여 레코드가 저장됨으로써 발생하는 변경 모두에 적용됩니다.

마찬가지로 트랜잭션이 중단되면, 트랜잭션의 범위에 있는 각 객체 저장소의 키 생성기 현재 번호는 트랜잭션이 시작되기 전의 값으로 되돌려집니다.

키 생성기의 현재 번호는 데이터베이스 작업이 되돌려진 결과가 아닌 한 절대로 감소하지 않습니다. 객체 저장소에서 레코드를 삭제해도 객체 저장소의 키 생성기에는 영향을 주지 않습니다. 예를 들어 clear() 메서드를 사용하여 객체 저장소의 모든 레코드를 지워도 객체 저장소 키 생성기의 현재 번호에는 영향을 주지 않습니다.

레코드를 저장할 때 레코드를 저장하는 호출에서 키를 지정하지 않으면 키가 생성됩니다.

객체 저장소 store에 대한 키를 생성하려면 다음 단계를 실행합니다.

  1. generator를 store의 키 생성기로 둡니다.

  2. key를 generator의 현재 번호로 둡니다.

  3. key가 253 (9007199254740992)보다 크면 실패를 반환합니다.

  4. generator의 현재 번호를 1 증가시킵니다.

  5. key를 반환합니다.

레코드를 저장할 때 레코드를 저장하는 호출에서 키를 지정하면, 연결된 키 생성기가 갱신될 수 있습니다.

객체 저장소 store와 key에 대해 키 생성기를 갱신할 수도 있는 단계를 수행하려면 다음 단계를 실행합니다.

  1. key의 유형이 숫자가 아니면 이 단계를 중단합니다.

  2. value를 key의 값으로 둡니다.

  3. value를 value와 253 (9007199254740992) 중 더 작은 값으로 설정합니다.

  4. value를 value보다 크지 않은 가장 큰 정수로 설정합니다.

  5. generator를 store의 키 생성기로 둡니다.

  6. value가 generator의 현재 번호 이상이면, generator의 현재 번호를 value + 1로 설정합니다.

참고: 키는 인라인 키를 사용하는 객체 저장소의 경우 객체 저장소의 키 경로가 가리키는 저장된 값의 속성을 설정하여 지정할 수 있고, 아웃오브라인 키를 사용하는 객체 저장소의 경우 레코드를 저장하는 호출에 키 인수를 전달하여 지정할 수 있습니다.

유형이 숫자인 지정된 키만 키 생성기의 현재 번호에 영향을 줄 수 있습니다. 유형이 날짜, 배열(포함하는 다른 키와 관계없이), 바이너리, 또는 문자열(숫자로 구문 분석할 수 있는지와 관계없이)인 키는 키 생성기의 현재 번호에 영향을 주지 않습니다. 유형이 숫자이고 값이 1보다 작은 키는 항상 현재 번호보다 작으므로 현재 번호에 영향을 주지 않습니다.

키 생성기의 현재 번호가 253 (9007199254740992)을 초과하면 이후 키 생성기를 사용하여 새 키를 생성하려는 모든 시도는 "ConstraintError" DOMException을 발생시킵니다. 명시적 키를 지정하여 객체 저장소에 레코드를 삽입하는 것은 여전히 가능하지만, 이러한 레코드에 키 생성기를 다시 사용할 수 있는 유일한 방법은 객체 저장소를 삭제하고 새로 생성하는 것입니다.

참고: 이 제한은 9007199254740992보다 큰 정수를 ECMAScript Number로 고유하게 표현할 수 없기 때문에 발생합니다. 예를 들어 ECMAScript에서는 9007199254740992 + 1 === 9007199254740992입니다.

키 생성기를 일반적인 방식으로 사용하는 한 이 제한은 문제가 되지 않습니다. 밤낮으로 초당 1000번 새 키를 생성하더라도 이 제한에 도달하기까지 285000년 이상 걸립니다.

그에 따른 실질적인 결과로, 객체 저장소에서 처음 생성되는 키는 항상 1이며(더 큰 숫자 키가 먼저 삽입된 경우는 제외), 객체 저장소에 대해 생성되는 키는 항상 저장소에서 가장 큰 숫자 키보다 큰 양의 정수입니다. 같은 객체 저장소에 대해 트랜잭션이 롤백되지 않는 한 동일한 키가 두 번 생성되지 않습니다.

각 객체 저장소에는 자체 키 생성기가 있습니다.

store1 = db.createObjectStore("store1", { autoIncrement: true });
store1.put("a"); // 키 1을 얻습니다
store2 = db.createObjectStore("store2", { autoIncrement: true });
store2.put("a"); // 키 1을 얻습니다
store1.put("b"); // 키 2를 얻습니다
store2.put("b"); // 키 2를 얻습니다

제약 조건 위반 또는 IO 오류로 삽입이 실패하면 키 생성기는 갱신되지 않습니다.

transaction.onerror = function(e) { e.preventDefault() };
store = db.createObjectStore("store1", { autoIncrement: true });
index = store.createIndex("index1", "ix", { unique: true });
store.put({ ix: "a"}); // 키 1을 얻습니다
store.put({ ix: "a"}); // 실패합니다
store.put({ ix: "b"}); // 키 2를 얻습니다

객체 저장소에서 항목을 제거해도 키 생성기에는 영향을 주지 않습니다. clear()가 호출되는 경우도 포함됩니다.

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // 키 1을 얻습니다
store.delete(1);
store.put("b"); // 키 2를 얻습니다
store.clear();
store.put("c"); // 키 3을 얻습니다
store.delete(IDBKeyRange.lowerBound(0));
store.put("d"); // 키 4를 얻습니다

명시적 키를 가진 항목을 삽입하는 것은 그 키가 숫자이고 마지막으로 생성된 키보다 큰 경우에만 키 생성기에 영향을 줍니다.

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // 키 1을 얻습니다
store.put("b", 3); // 키 3을 사용합니다
store.put("c"); // 키 4를 얻습니다
store.put("d", -10); // 키 -10을 사용합니다
store.put("e"); // 키 5를 얻습니다
store.put("f", 6.00001); // 키 6.0001을 사용합니다
store.put("g"); // 키 7을 얻습니다
store.put("f", 8.9999); // 키 8.9999를 사용합니다
store.put("g"); // 키 9를 얻습니다
store.put("h", "foo"); // 키 "foo"를 사용합니다
store.put("i"); // 키 10을 얻습니다
store.put("j", [1000]); // 키 [1000]을 사용합니다
store.put("k"); // 키 11을 얻습니다
// 객체 저장소가 keyPath를 사용하고 명시적 키가 객체 안에
// 인라인으로 전달된 경우에도 이 모든 동작은 동일합니다

트랜잭션을 중단하면 트랜잭션 중 발생한 키 생성기의 모든 증가가 롤백됩니다. 이는 충돌로 인해 발생하는 롤백에서는 증가된 키 생성기 값을 커밋할 기회가 없으므로 모든 롤백을 일관되게 만들기 위한 것입니다.

db.createObjectStore("store", { autoIncrement: true });
trans1 = db.transaction(["store"], "readwrite");
store_t1 = trans1.objectStore("store");
store_t1.put("a"); // 키 1을 얻습니다
store_t1.put("b"); // 키 2를 얻습니다
trans1.abort();
trans2 = db.transaction(["store"], "readwrite");
store_t2 = trans2.objectStore("store");
store_t2.put("c"); // 키 1을 얻습니다
store_t2.put("d"); // 키 2를 얻습니다

다음 예에서는 인라인 키와 키 생성기를 사용하여 객체 저장소에 객체를 저장하려 할 때의 서로 다른 동작을 보여 줍니다.

다음 조건이 참이면:

그러면 키 생성기가 제공한 값이 키 값을 채우는 데 사용됩니다. 아래 예에서 객체 저장소의 키 경로는 "foo.bar"입니다. 실제 객체에는 bar 속성의 값이 없는 { foo: {} }가 있습니다. 객체가 객체 저장소에 저장될 때 bar 속성에는 값 1이 할당됩니다. 이는 키 생성기가 다음에 생성하는 키이기 때문입니다.

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
};

다음 조건이 참이면:

그러면 키 경로 속성과 연결된 값이 사용됩니다. 자동 생성된 키는 사용되지 않습니다. 아래 예에서 객체 저장소의 키 경로는 "foo.bar"입니다. 실제 객체에는 bar 속성 값이 10인 { foo: { bar: 10} }이 있습니다. 객체가 객체 저장소에 저장될 때 bar 속성은 값 10을 그대로 유지합니다. 이것이 키 값이기 때문입니다.

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: { bar: 10 } }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 10);
};

다음 예에서는 지정된 인라인 키가 키 경로를 통해 정의되지만 이에 일치하는 속성이 없는 경우를 보여 줍니다. 이때 키 생성기가 제공한 값이 키 값을 채우는 데 사용되며, 시스템은 계층 구조 체인의 속성 종속성을 충족하기 위해 필요한 만큼의 속성을 생성할 책임이 있습니다. 아래 예에서 객체 저장소의 키 경로는 "foo.bar.baz"입니다. 실제 객체에는 foo 속성의 값이 없는 { zip: {} }가 있습니다. 객체가 객체 저장소에 저장될 때 foo, bar, baz 속성은 foo.bar.baz에 값을 할당할 수 있을 때까지 각각 이전 속성의 자식으로 생성됩니다. foo.bar.baz의 값은 객체 저장소가 다음으로 생성하는 키입니다.

const store = db.createObjectStore("store", { keyPath: "foo.bar.baz",
                                              autoIncrement: true });
store.put({ zip: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
  store.get(key).onsuccess = function(e) {
    const value = e.target.result;
    // value는 다음과 같습니다: { zip: {}, foo: { bar: { baz: 1 } } }
    console.assert(value.foo.bar.baz === 1);
  };
};

원시 값에 속성을 저장하려고 하면 실패하고 오류가 발생합니다. 아래 첫 번째 예에서 객체 저장소의 키 경로는 "foo"입니다. 실제 객체는 값이 4인 원시 값입니다. 해당 원시 값에 속성을 정의하려는 시도는 실패합니다.

const store = db.createObjectStore("store", { keyPath: "foo", autoIncrement: true });

// 키 생성은 이 원시 값에 키 경로 속성을 생성하여
// 저장하려고 시도합니다.
store.put(4); // DataError를 던집니다

2.12. 레코드 스냅샷

레코드 스냅샷은 객체 저장소 레코드 또는 인덱스 레코드에서 복사된 키와 값을 포함합니다.

레코드 스냅샷에는 키인 키가 있습니다.

레코드 스냅샷에는 값인 값이 있습니다.

참고: 인덱스 레코드의 경우 스냅샷의 값은 레코드의 참조된 값의 복사본입니다. 객체 저장소 레코드의 경우 스냅샷의 값은 레코드의 값입니다.

레코드 스냅샷에는 또한 키인 기본 키가 있습니다.

참고: 인덱스 레코드의 경우 스냅샷의 기본 키는 레코드의 값이며, 이는 인덱스의 참조되는 객체 저장소에 있는 레코드의 키입니다. 객체 저장소 레코드의 경우 스냅샷의 기본 키와 키는 동일한 키이며, 이는 레코드의 키입니다.

3. 예외

이 문서에서 사용되는 각 예외는 [WEBIDL]에 정의된 DOMException 또는 DOMException에서 파생된 인터페이스입니다.

아래 표에는 이 문서에서 사용되는 DOMException 이름과 함께 해당 예외의 사용법에 대한 설명이 나열되어 있습니다.

유형 설명
AbortError 요청이 중단되었습니다.
ConstraintError 제약 조건이 충족되지 않아 트랜잭션의 변경 작업이 실패했습니다.
DataCloneError 저장 중인 데이터를 내부 구조화 복제 알고리즘으로 복제할 수 없습니다.
DataError 작업에 제공된 데이터가 요구 사항을 충족하지 않습니다.
InvalidAccessError 객체에 대해 유효하지 않은 작업이 수행되었습니다.
InvalidStateError 허용되지 않는 객체에서 작업이 호출되었거나 허용되지 않는 시점에 호출되었거나, 삭제 또는 제거된 소스 객체에 요청이 이루어졌습니다.
NotFoundError 요청된 데이터베이스 객체를 찾을 수 없어 작업이 실패했습니다.
NotReadableError 요청된 데이터를 포함하는 기본 스토리지를 읽을 수 없어 작업이 실패했습니다.
SyntaxError keyPath 인수에 유효하지 않은 키 경로가 포함되어 있습니다.
ReadOnlyError 읽기 전용 트랜잭션에서 변경 작업을 시도했습니다.
TransactionInactiveError 현재 활성 상태가 아니거나 완료된 트랜잭션에 요청이 배치되었습니다.
UnknownError 데이터베이스 자체와 관련이 없거나 다른 오류로 처리되지 않는 일시적인 이유로 작업이 실패했습니다.
VersionError 기존 버전보다 낮은 버전을 사용하여 데이터베이스를 열려고 시도했습니다.

위의 DOMException 이름 외에도, 남은 저장 공간이 충분하지 않거나 저장소 할당량에 도달했고 사용자가 데이터베이스에 더 많은 공간을 제공하는 것을 거부하여 작업이 실패한 경우에는 QuotaExceededError 예외 유형을 사용해야 합니다.

참고: 여러 Indexed DB 작업이 같은 유형의 오류를 던질 수 있고, 단일 작업조차도 여러 이유로 같은 유형의 오류를 던질 수 있으므로 구현에서는 개발자가 오류의 원인을 식별할 수 있도록 더 구체적인 메시지를 제공하는 것이 권장됩니다.

4. API

API 메서드는 호출 스레드를 차단하지 않고 반환합니다. 모든 비동기 작업은 즉시 IDBRequest 인스턴스를 반환합니다. 이 객체는 처음에는 작업 결과에 대한 정보를 포함하지 않습니다. 정보를 사용할 수 있게 되면 요청에서 이벤트가 발생하고 IDBRequest 인스턴스의 속성을 통해 해당 정보를 사용할 수 있게 됩니다.

이 태스크들의 태스크 소스는 데이터베이스 접근 태스크 소스입니다.

데이터베이스 태스크를 큐에 추가하려면 데이터베이스 접근 태스크 소스에서 태스크를 큐에 추가합니다.

4.1. IDBRequest 인터페이스

IDBRequest 인터페이스는 [HTML]의 이벤트 핸들러 IDL 속성을 사용하여 데이터베이스 및 데이터베이스 객체에 대한 비동기 요청 결과에 접근할 수 있는 수단을 제공합니다.

비동기 요청을 수행하는 모든 메서드는 이벤트를 통해 요청한 애플리케이션에 결과를 전달하는 IDBRequest 객체를 반환합니다. 이 설계는 어느 시점이든 어떤 데이터베이스에서든 임의의 수의 요청이 활성 상태일 수 있음을 의미합니다.

다음 예에서는 데이터베이스를 비동기적으로 엽니다. 다양한 상황에 대응하기 위해 여러 이벤트 핸들러를 등록합니다.

const request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {...};
request.onerror = function(evt) {...};
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonly attribute any result;
  readonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // 이벤트 핸들러:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending",
  "done"
};
request . result

요청이 완료되면 결과를 반환하고, 요청이 실패한 경우 undefined를 반환합니다. 요청이 아직 보류 중이면 "InvalidStateError" DOMException을 던집니다.

request . error

요청이 완료되면 오류(DOMException)를 반환하고, 요청이 성공한 경우 null을 반환합니다. 요청이 아직 보류 중이면 "InvalidStateError" DOMException을 던집니다.

request . source

요청이 이루어진 IDBObjectStore, IDBIndex, 또는 IDBCursor를 반환하고, 열기 요청인 경우 null을 반환합니다.

request . transaction

요청이 이루어진 IDBTransaction을 반환합니다. 이것이 열기 요청이면, 업그레이드 트랜잭션이 활성 상태인 동안에는 해당 트랜잭션을 반환하고, 그렇지 않으면 null을 반환합니다.

request . readyState

요청이 완료될 때까지 "pending"을 반환하고, 그 후에는 "done"을 반환합니다.

result getter 단계는 다음과 같습니다.
  1. this의 완료 플래그가 false이면, "InvalidStateError" DOMException을 던집니다.

  2. this의 결과를 반환하고, 요청에서 오류가 발생한 경우 undefined를 반환합니다.

error getter 단계는 다음과 같습니다.
  1. this의 완료 플래그가 false이면, "InvalidStateError" DOMException을 던집니다.

  2. this의 오류를 반환하고, 오류가 발생하지 않은 경우 null을 반환합니다.

source getter 단계는 this의 소스를 반환하고, 소스가 설정되지 않은 경우 null을 반환하는 것입니다.

transaction getter 단계는 this의 트랜잭션을 반환하는 것입니다.

참고: transaction getter는 open()에서 반환된 요청과 같은 특정 요청에서 null을 반환할 수 있습니다.

readyState getter 단계는 this의 완료 플래그가 false이면 "pending"을 반환하고, 그렇지 않으면 "done"을 반환하는 것입니다.

onsuccess 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 success입니다.

onerror 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 error 이벤트입니다.

열기 요청을 반환하는 IDBDatabase의 메서드는 blocked 및 upgradeneeded 이벤트를 수신할 수 있도록 확장 인터페이스를 사용합니다.

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // 이벤트 핸들러:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};

onblocked 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 blocked입니다.

onupgradeneeded 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 upgradeneeded입니다.

4.2. 이벤트 인터페이스

이 명세는 다음 사용자 정의 인터페이스를 사용하여 이벤트를 발생시킵니다.

[Exposed=(Window,Worker)]
interface IDBVersionChangeEvent : Event {
  constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
  readonly attribute unsigned long long oldVersion;
  readonly attribute unsigned long long? newVersion;
};

dictionary IDBVersionChangeEventInit : EventInit {
  unsigned long long oldVersion = 0;
  unsigned long long? newVersion = null;
};

oldVersion getter 단계는 초기화된 값을 반환하는 것입니다. 이는 데이터베이스의 이전 버전을 나타냅니다.

newVersion getter 단계는 초기화된 값을 반환하는 것입니다. 이는 데이터베이스의 새 버전을 나타내며, 데이터베이스가 삭제 중인 경우 null입니다. 데이터베이스 업그레이드 단계를 참조하세요.

이벤트는 DOM § 2.5 이벤트 구성에 정의된 대로 구성됩니다.

oldVersion 및 newVersion이 주어졌을 때 target에서 e라는 이름의 버전 변경 이벤트를 발생시키려면 다음 단계를 실행합니다.

  1. event를 IDBVersionChangeEvent를 사용하여 이벤트를 생성한 결과로 둡니다.

  2. event의 type 속성을 e로 설정합니다.

  3. event의 bubbles 및 cancelable 속성을 false로 설정합니다.

  4. event의 oldVersion 속성을 oldVersion으로 설정합니다.

  5. event의 newVersion 속성을 newVersion으로 설정합니다.

  6. legacyOutputDidListenersThrowFlag를 false로 둡니다.

  7. legacyOutputDidListenersThrowFlag와 함께 target에서 event를 디스패치합니다.

  8. legacyOutputDidListenersThrowFlag를 반환합니다.

    참고: 이 알고리즘의 반환 값이 항상 사용되는 것은 아닙니다.

4.3. IDBFactory 인터페이스

데이터베이스 객체에는 IDBFactory 인터페이스의 메서드를 통해 접근합니다. 이 인터페이스를 구현하는 단일 객체가 Indexed DB 작업을 지원하는 환경의 전역 범위에 존재합니다.

partial interface mixin WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};

indexedDB 속성은 애플리케이션에 인덱스드 데이터베이스의 기능에 접근할 수 있는 메커니즘을 제공합니다.

[Exposed=(Window,Worker)]
interface IDBFactory {
  [NewObject] IDBOpenDBRequest open(DOMString name,
                                    optional [EnforceRange] unsigned long long version);
  [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);

  Promise<sequence<IDBDatabaseInfo>> databases();

  short cmp(any first, any second);
};

dictionary IDBDatabaseInfo {
  DOMString name;
  unsigned long long version;
};
request = indexedDB . open(name)

지정된 데이터베이스에 현재 버전으로 연결을 열려고 시도하며, 아직 존재하지 않는 경우 버전 1로 엽니다. 요청이 성공하면 request의 result는 연결이 됩니다.

request = indexedDB . open(name, version)

지정된 version으로 지정된 데이터베이스에 연결을 열려고 시도합니다. 데이터베이스가 이미 더 낮은 버전으로 존재하고 versionchange 이벤트에 응답하여 닫히지 않는 열린 연결이 있는 경우, 요청은 모든 연결이 닫힐 때까지 차단되고 그 후 업그레이드가 수행됩니다. 데이터베이스가 이미 더 높은 버전으로 존재하면 요청이 실패합니다. 요청이 성공하면 request의 result는 연결이 됩니다.

request = indexedDB . deleteDatabase(name)

지정된 데이터베이스를 삭제하려고 시도합니다. 데이터베이스가 이미 존재하고 versionchange 이벤트에 응답하여 닫히지 않는 열린 연결이 있으면, 요청은 모든 연결이 닫힐 때까지 차단됩니다. 요청이 성공하면 request의 result는 null이 됩니다.

result = await indexedDB . databases()

스토리지 키 내 데이터베이스의 이름과 버전에 대한 스냅샷을 제공하는 객체 목록으로 이행되는 프로미스를 반환합니다.

이 API는 웹 애플리케이션이 데이터베이스 사용을 조사하기 위한 것으로, 예를 들어 사이트 코드의 이전 버전에서 남은 데이터를 정리할 때 사용할 수 있습니다. 결과는 스냅샷이라는 점에 유의하세요. 이 컨텍스트 또는 다른 컨텍스트에서 데이터베이스를 생성, 업그레이드 또는 삭제하는 요청과 관련하여 데이터 수집 순서나 응답 전달 순서에 대한 보장은 없습니다.

open(name, version) 메서드 단계는 다음과 같습니다.

  1. version이 0(영)이면 TypeError를 던집니다.

  2. environment를 this의 관련 설정 객체로 둡니다.

  3. storageKey를 environment가 주어졌을 때 스토리지 키 가져오기를 실행한 결과로 둡니다. 실패가 반환되면 "SecurityError" DOMException을 던지고 이 단계를 중단합니다.

  4. request를 새로운 열기 요청으로 둡니다.

  5. 다음 단계를 병렬로 실행합니다.

    1. result를 storageKey, name, 주어진 경우 version, 그렇지 않으면 undefined, 그리고 request를 사용하여 데이터베이스 연결을 연 결과로 둡니다.

      version이 주어지지 않으면 어떻게 되나요? version이 주어지지 않았고 해당 이름의 데이터베이스가 이미 존재하면 버전을 변경하지 않고 연결이 열립니다. version이 주어지지 않았고 해당 이름의 데이터베이스가 존재하지 않으면, 새 데이터베이스가 버전 1로 생성됩니다.
    2. request의 처리됨 플래그를 true로 설정합니다.

    3. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

      1. result가 오류이면 다음을 수행합니다.

        1. request의 결과를 undefined로 설정합니다.

        2. request의 오류를 result로 설정합니다.

        3. request의 완료 플래그를 true로 설정합니다.

        4. request에서 error라는 이름의 이벤트를 발생시키고, 그 bubbles 및 cancelable 속성을 true로 초기화합니다.

      2. 그렇지 않으면 다음을 수행합니다.

        1. request의 결과를 result로 설정합니다.

        2. request의 완료 플래그를 true로 설정합니다.

        3. request에서 success라는 이름의 이벤트를 발생시킵니다.

        참고: 위 단계로 인해 업그레이드 트랜잭션이 실행되었다면, 이 단계들은 해당 트랜잭션이 완료된 후 실행됩니다. 이렇게 하면 또 다른 버전 업그레이드가 곧 수행될 경우 연결에서 success 이벤트가 먼저 발생하여 스크립트가 versionchange 이벤트에 대한 리스너를 등록할 기회를 얻습니다.

        왜 성공 이벤트 발생 또는 오류 이벤트 발생 단계가 사용되지 않나요? 이 시점에는 요청과 연결된 트랜잭션이 없으므로, 디스패치 전에 연결된 트랜잭션을 활성화하고 디스패치 후 트랜잭션을 비활성화하는 해당 단계들은 적용되지 않습니다.
  6. request에 대한 새로운 IDBOpenDBRequest 객체를 반환합니다.

deleteDatabase(name) 메서드 단계는 다음과 같습니다.

  1. environment를 this의 관련 설정 객체로 둡니다.

  2. storageKey를 environment가 주어졌을 때 스토리지 키 가져오기를 실행한 결과로 둡니다. 실패가 반환되면 "SecurityError" DOMException을 던지고 이 단계를 중단합니다.

  3. request를 새로운 열기 요청으로 둡니다.

  4. 다음 단계를 병렬로 실행합니다.

    1. result를 storageKey, name, 그리고 request를 사용하여 데이터베이스를 삭제한 결과로 둡니다.

    2. request의 처리됨 플래그를 true로 설정합니다.

    3. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

      1. result가 오류이면 request의 오류를 result로 설정하고, request의 완료 플래그를 true로 설정하고, request에서 error라는 이름의 이벤트를 발생시키며, 그 bubbles 및 cancelable 속성을 true로 초기화합니다.

      2. 그렇지 않으면 request의 결과를 undefined로 설정하고, request의 완료 플래그를 true로 설정하고, request에서 result 및 null과 함께 success라는 이름의 버전 변경 이벤트를 발생시킵니다.

        왜 성공 이벤트 발생 또는 오류 이벤트 발생 단계가 사용되지 않나요? 요청과 연결된 트랜잭션이 없으므로, 디스패치 전에 연결된 트랜잭션을 활성화하고 디스패치 후 트랜잭션을 비활성화하는 해당 단계들은 적용되지 않습니다.

        또한 여기의 success 이벤트는 IDBVersionChangeEvent이며, oldVersion 및 newVersion 세부 정보를 포함합니다.

  5. request에 대한 새로운 IDBOpenDBRequest 객체를 반환합니다.

databases() 메서드 단계는 다음과 같습니다.

  1. environment를 this의 관련 설정 객체로 둡니다.

  2. storageKey를 environment가 주어졌을 때 스토리지 키 가져오기를 실행한 결과로 둡니다. 실패가 반환되면 "SecurityError" DOMException으로 거부된 프로미스를 반환합니다.

  3. p를 새 프로미스로 둡니다.

  4. 다음 단계를 병렬로 실행합니다.

    1. databases를 storageKey에 있는 데이터베이스의 집합으로 둡니다. 어떤 이유로든 이를 결정할 수 없으면 적절한 오류(예: "UnknownError" DOMException)로 p를 거부하도록 데이터베이스 태스크를 큐에 추가하고 이 단계를 종료합니다.

    2. result를 새로운 목록으로 둡니다.

    3. databases의 각 db에 대해 다음을 수행합니다.

      1. db의 버전이 0이면 계속합니다.

      2. info를 새로운 IDBDatabaseInfo 사전으로 둡니다.

      3. info의 name 사전 멤버를 db의 이름으로 설정합니다.

      4. info의 version 사전 멤버를 db의 버전으로 설정합니다.

      5. info를 result에 추가합니다.

    4. result로 p를 이행하도록 데이터베이스 태스크를 큐에 추가합니다.

  5. p를 반환합니다.

🚧 databases() 메서드는 이 판에서 새로 추가되었습니다. Chrome 71, Edge 79, Firefox 126, Safari 14에서 지원됩니다. 🚧
result = indexedDB . cmp(key1, key2)

두 값을 키로 비교합니다. key1이 key2보다 앞서면 -1, key2가 key1보다 앞서면 1, 키가 같으면 0을 반환합니다.

입력 중 하나라도 유효한 키가 아니면 "DataError" DOMException을 던집니다.

cmp(first, second) 메서드 단계는 다음과 같습니다.

  1. a를 first를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. a가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  3. b를 second를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  4. b가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  5. a와 b를 사용해 두 키를 비교한 결과를 반환합니다.

4.4. IDBDatabase 인터페이스

IDBDatabase 인터페이스는 데이터베이스에 대한 연결을 나타냅니다.

IDBDatabase 객체와 연결된 연결의 닫기 보류 플래그가 false이고, 유형이 abort, error, 또는 versionchange 중 하나인 이벤트 리스너가 하나 이상 등록되어 있으면 가비지 컬렉션되어서는 안 됩니다. IDBDatabase 객체가 가비지 컬렉션되면 연결된 연결은 닫혀야 합니다.

[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
  readonly attribute DOMString name;
  readonly attribute unsigned long long version;
  readonly attribute DOMStringList objectStoreNames;

  [NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
                                         optional IDBTransactionMode mode = "readonly",
                                         optional IDBTransactionOptions options = {});
  undefined close();

  [NewObject] IDBObjectStore createObjectStore(
    DOMString name,
    optional IDBObjectStoreParameters options = {});
  undefined deleteObjectStore(DOMString name);

  // 이벤트 핸들러:
  attribute EventHandler onabort;
  attribute EventHandler onclose;
  attribute EventHandler onerror;
  attribute EventHandler onversionchange;
};

enum IDBTransactionDurability { "default", "strict", "relaxed" };

dictionary IDBTransactionOptions {
  IDBTransactionDurability durability = "default";
};

dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};
connection . name

데이터베이스의 이름을 반환합니다.

connection . version

데이터베이스의 버전을 반환합니다.

name getter 단계는 this와 연결된 데이터베이스의 이름을 반환하는 것입니다.

참고: name 속성은 this의 닫기 보류 플래그가 true인 경우에도 이 이름을 반환합니다. 다시 말해 이 속성의 값은 IDBDatabase 인스턴스의 수명 동안 일정하게 유지됩니다.

version getter 단계는 this의 버전을 반환하는 것입니다.

이것은 데이터베이스의 버전과 같나요? 연결이 열려 있는 동안에는 연결된 데이터베이스의 버전과 같습니다. 그러나 연결이 닫힌 후에는 이 속성에 이후 업그레이드 트랜잭션에서 이루어진 변경이 반영되지 않습니다.
connection . objectStoreNames

데이터베이스에 있는 객체 저장소의 이름 목록을 반환합니다.

store = connection . createObjectStore(name [, options])

주어진 name 및 options로 새로운 객체 저장소를 생성하고 새로운 IDBObjectStore를 반환합니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

connection . deleteObjectStore(name)

주어진 name을 가진 객체 저장소를 삭제합니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

objectStoreNames getter 단계는 다음과 같습니다.
  1. names를 this의 객체 저장소 집합에 있는 객체 저장소의 이름의 목록으로 둡니다.

  2. names를 사용하여 정렬된 이름 목록을 생성한 결과(DOMStringList)를 반환합니다.

이것은 데이터베이스의 객체 저장소 이름과 같나요? 연결이 열려 있는 동안에는 연결된 데이터베이스의 객체 저장소 이름과 같습니다. 그러나 연결이 닫힌 후에는 이 속성에 이후 업그레이드 트랜잭션에서 이루어진 변경이 반영되지 않습니다.

createObjectStore(name, options) 메서드 단계는 다음과 같습니다.

  1. database를 this와 연결된 데이터베이스로 둡니다.

  2. database의 업그레이드 트랜잭션이 null이 아니면 이를 transaction으로 두고, 그렇지 않으면 "InvalidStateError" DOMException을 던집니다.

  3. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  4. keyPath를 options의 keyPath 멤버가 undefined 또는 null이 아니면 그 멤버로 두고, 그렇지 않으면 null로 둡니다.

  5. keyPath가 null이 아니고 유효한 키 경로도 아니면 "SyntaxError" DOMException을 던집니다.

  6. database에 name이라는 이름의 객체 저장소가 이미 존재하면 "ConstraintError" DOMException을 던집니다.

  7. autoIncrement를 options의 autoIncrement 멤버로 둡니다.

  8. autoIncrement가 true이고 keyPath가 빈 문자열 또는 임의의 시퀀스(비어 있거나 그렇지 않은 경우 모두)이면 "InvalidAccessError" DOMException을 던집니다.

  9. store를 database의 새로운 객체 저장소로 둡니다. 생성된 객체 저장소의 이름을 name으로 설정합니다. autoIncrement가 true이면 생성된 객체 저장소는 키 생성기를 사용합니다. keyPath가 null이 아니면 생성된 객체 저장소의 키 경로를 keyPath로 설정합니다.

  10. store 및 transaction과 연결된 새로운 객체 저장소 핸들을 반환합니다.

이 메서드는 연결된 데이터베이스에 주어진 이름을 가진 새로운 객체 저장소를 생성하고 반환합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출해야 한다는 점에 유의하세요.

이 메서드는 호출된 IDBDatabase 인스턴스의 objectStoreNames 속성을 동기적으로 수정합니다.

일부 구현에서는 createObjectStore() 메서드가 반환된 후 객체 저장소를 생성하기 위한 태스크를 큐에 추가한 뒤 구현에서 문제가 발생할 수 있습니다. 예를 들어 새로 생성된 객체 저장소에 대한 메타데이터를 데이터베이스에 비동기적으로 삽입하는 구현이나, 할당량 문제로 사용자에게 권한을 요청해야 할 수 있는 구현이 있습니다. 이러한 구현도 여전히 IDBObjectStore 객체를 생성하고 반환해야 하며, 구현에서 객체 저장소 생성이 실패했다고 판단하면 적절한 오류를 사용하여 트랜잭션 중단 단계를 실행해 트랜잭션을 중단해야 합니다. 예를 들어 객체 저장소 생성이 할당량 문제로 실패한 경우 QuotaExceededError를 오류로 사용해야 합니다.

deleteObjectStore(name) 메서드 단계는 다음과 같습니다.

  1. database를 this와 연결된 데이터베이스로 둡니다.

  2. database의 업그레이드 트랜잭션이 null이 아니면 이를 transaction으로 두고, 그렇지 않으면 "InvalidStateError" DOMException을 던집니다.

  3. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  4. store를 database에서 name이라는 이름의 객체 저장소로 두고, 그러한 저장소가 없으면 "NotFoundError" DOMException을 던집니다.

  5. this의 객체 저장소 집합에서 store를 제거합니다.

  6. store 및 transaction과 연결된 객체 저장소 핸들이 있으면 그 인덱스 집합에서 모든 항목을 제거합니다.

  7. store를 파기합니다.

이 메서드는 연결된 데이터베이스에서 주어진 이름을 가진 객체 저장소를 파기합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출해야 한다는 점에 유의하세요.

이 메서드는 호출된 IDBDatabase 인스턴스의 objectStoreNames 속성을 동기적으로 수정합니다.

transaction = connection . transaction(scope [, mode [, options ] ])

주어진 scope(단일 객체 저장소 이름 또는 이름의 배열일 수 있음), mode("readonly" 또는 "readwrite"), 그리고 durability ("default", "strict" 또는 "relaxed")를 포함한 추가 options를 가진 새로운 트랜잭션을 반환합니다.

기본 mode는 "readonly"이고 기본 durability는 "default"입니다.

connection . close()

실행 중인 모든 트랜잭션이 완료되면 연결을 닫습니다.

transaction(storeNames, mode, options) 메서드 단계는 다음과 같습니다.

  1. 연결과 활성 상태의 업그레이드 트랜잭션이 연결되어 있으면 "InvalidStateError" DOMException을 던집니다.

  2. this의 닫기 보류 플래그가 true이면 "InvalidStateError" DOMException을 던집니다.

  3. storeNames가 시퀀스이면 그 안의 고유한 문자열 집합을, 그렇지 않으면 storeNames와 같은 하나의 문자열을 포함하는 집합을 scope로 둡니다.

  4. scope의 어떤 문자열이라도 연결된 데이터베이스의 객체 저장소 이름이 아니면 "NotFoundError" DOMException을 던집니다.

  5. scope가 비어 있으면 "InvalidAccessError" DOMException을 던집니다.

  6. mode가 "readonly" 또는 "readwrite"가 아니면 TypeError를 던집니다.

  7. transaction을 이 연결, mode, options의 durability 멤버, 그리고 scope에 이름이 지정된 객체 저장소 집합으로 새로 생성된 트랜잭션으로 둡니다.

  8. transaction의 정리 이벤트 루프를 현재 이벤트 루프로 설정합니다.

  9. transaction을 나타내는 IDBTransaction 객체를 반환합니다.

🚧 durability 옵션은 이 판에서 새로 추가되었습니다. Chrome 82, Edge 82, Firefox 126, Safari 15에서 지원됩니다. 🚧

참고: 생성된 transaction은 수명 규칙을 따릅니다.

close() 메서드 단계는 다음과 같습니다.

  1. 이 연결을 사용하여 데이터베이스 연결 닫기를 실행합니다.

참고: 연결은 아직 완료되지 않은 모든 트랜잭션이 완료될 때까지 실제로 닫히지 않습니다. 이후 close() 호출은 아무 효과가 없습니다.

onabort 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 abort입니다.

onclose 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 close입니다.

onerror 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 error입니다.

onversionchange 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 versionchange입니다.

4.5. IDBObjectStore 인터페이스

IDBObjectStore 인터페이스는 객체 저장소 핸들을 나타냅니다.

[Exposed=(Window,Worker)]
interface IDBObjectStore {
  attribute DOMString name;
  readonly attribute any keyPath;
  readonly attribute DOMStringList indexNames;
  [SameObject] readonly attribute IDBTransaction transaction;
  readonly attribute boolean autoIncrement;

  [NewObject] IDBRequest put(any value, optional any key);
  [NewObject] IDBRequest add(any value, optional any key);
  [NewObject] IDBRequest delete(any query);
  [NewObject] IDBRequest clear();
  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any queryOrOptions,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");

  IDBIndex index(DOMString name);

  [NewObject] IDBIndex createIndex(DOMString name,
                                   (DOMString or sequence<DOMString>) keyPath,
                                   optional IDBIndexParameters options = {});
  undefined deleteIndex(DOMString name);
};

dictionary IDBIndexParameters {
  boolean unique = false;
  boolean multiEntry = false;
};

dictionary IDBGetAllOptions {
  any query = null;
  [EnforceRange] unsigned long count;
  IDBCursorDirection direction = "next";
};
store . name

저장소의 이름을 반환합니다.

store . name = newName

저장소의 이름을 newName으로 갱신합니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

store . keyPath

저장소의 키 경로를 반환하고, 없으면 null을 반환합니다.

store . indexNames

저장소의 인덱스 이름 목록을 반환합니다.

store . transaction

연결된 트랜잭션을 반환합니다.

store . autoIncrement

저장소에 키 생성기가 있으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

name getter 단계는 this의 이름을 반환하는 것입니다.

이것은 객체 저장소의 이름과 같나요? 트랜잭션이 완료되지 않은 동안에는 연결된 객체 저장소의 이름과 같습니다. 그러나 트랜잭션이 완료되면 이 속성에는 이후 업그레이드 트랜잭션에서 이루어진 변경이 반영되지 않습니다.

name setter 단계는 다음과 같습니다.

  1. name을 주어진 값으로 둡니다.

  2. transaction을 this의 트랜잭션으로 둡니다.

  3. store를 this의 객체 저장소로 둡니다.

  4. store가 삭제된 경우, "InvalidStateError" DOMException을 던집니다.

  5. transaction이 업그레이드 트랜잭션이 아니면 "InvalidStateError" DOMException을 던집니다.

  6. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  7. store의 이름이 name과 같으면 이 단계를 종료합니다.

  8. store의 데이터베이스에 name이라는 이름의 객체 저장소가 이미 존재하면 "ConstraintError" DOMException을 던집니다.

  9. store의 이름을 name으로 설정합니다.

  10. this의 이름을 name으로 설정합니다.

keyPath getter 단계는 this의 객체 저장소의 키 경로를 반환하고, 없으면 null을 반환하는 것입니다. 키 경로는 [WEBIDL]에 따라 문자열인 경우 DOMString으로, 문자열 목록인 경우 sequence<DOMString>으로 변환됩니다.

참고: 반환된 값은 객체 저장소가 생성될 때 사용된 것과 동일한 인스턴스가 아닙니다. 그러나 이 속성이 객체(구체적으로 Array)를 반환하는 경우에는 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 객체의 속성을 변경해도 객체 저장소에는 영향을 주지 않습니다.

indexNames getter 단계는 다음과 같습니다.
  1. names를 this의 인덱스 집합에 있는 인덱스의 이름의 목록으로 둡니다.

  2. names를 사용하여 정렬된 이름 목록을 생성한 결과(DOMStringList)를 반환합니다.

이것은 객체 저장소의 인덱스 이름 목록과 같나요? 트랜잭션이 완료되지 않은 동안에는 연결된 객체 저장소의 인덱스 이름 목록과 같습니다. 그러나 트랜잭션이 완료되면 이 속성에는 이후 업그레이드 트랜잭션에서 이루어진 변경이 반영되지 않습니다.

transaction getter 단계는 this의 트랜잭션을 반환하는 것입니다.

autoIncrement getter 단계는 this의 객체 저장소에 키 생성기가 있으면 true를, 그렇지 않으면 false를 반환하는 것입니다.

다음 메서드들은 읽기 전용 트랜잭션 내에서 호출되면 "ReadOnlyError" DOMException을 던지고, 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = store . put(value [, key])
request = store . add(value [, key])

주어진 value와 key를 사용하여 store의 레코드를 추가하거나 갱신합니다.

저장소가 인라인 키를 사용하고 key가 지정되면 "DataError" DOMException이 발생합니다.

put()을 사용하는 경우 해당 키를 가진 기존 레코드가 모두 대체됩니다. add()를 사용하고 해당 키를 가진 레코드가 이미 존재하면 request가 실패하고 request의 error가 "ConstraintError" DOMException으로 설정됩니다.

성공하면 request의 result는 레코드의 키가 됩니다.

request = store . delete(query)

query의 주어진 키 또는 주어진 키 범위에 있는 store의 레코드를 삭제합니다.

성공하면 request의 result는 undefined가 됩니다.

request = store . clear()

store의 모든 레코드를 삭제합니다.

성공하면 request의 result는 undefined가 됩니다.

put(value, key) 메서드 단계는 this, value, key 및 false인 no-overwrite flag와 함께 추가 또는 저장을 실행한 결과를 반환하는 것입니다.

add(value, key) 메서드 단계는 this, value, key 및 true인 no-overwrite flag와 함께 추가 또는 저장을 실행한 결과를 반환하는 것입니다.

handle, value, key 및 no-overwrite flag와 함께 추가 또는 저장하려면 다음 단계를 실행합니다.

  1. transaction을 handle의 트랜잭션으로 둡니다.

  2. store를 handle의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. transaction이 읽기 전용 트랜잭션이면 "ReadOnlyError" DOMException을 던집니다.

  6. store가 인라인 키를 사용하고 key가 주어졌으면 "DataError" DOMException을 던집니다.

  7. store가 아웃오브라인 키를 사용하고 키 생성기가 없으며 key가 주어지지 않았으면 "DataError" DOMException을 던집니다.

  8. key가 주어졌으면 다음을 수행합니다.

    1. r을 key를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

    2. r이 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

    3. key를 r로 둡니다.

  9. targetRealm을 사용자 에이전트가 정의한 Realm으로 둡니다.

  10. clone을 transaction 동안 targetRealm에서 value을 복제한 것으로 둡니다. 모든 예외를 다시 던집니다.

    왜 값의 복사본을 생성하나요? 값은 저장될 때 직렬화됩니다. 여기에서 이를 복사본으로 취급하면 이 명세의 다른 알고리즘이 이를 ECMAScript 값으로 취급할 수 있지만, 동작 차이를 관찰할 수 없는 경우 구현은 이를 최적화할 수 있습니다.
  11. store가 인라인 키를 사용하면 다음을 수행합니다.

    1. kpk를 clone 및 store의 키 경로를 사용하여 키 경로를 사용하여 값에서 키를 추출한 결과로 둡니다. 모든 예외를 다시 던집니다.

    2. kpk가 유효하지 않으면 "DataError" DOMException을 던집니다.

    3. kpk가 failure가 아니면 key를 kpk로 둡니다.

    4. 그렇지 않으면(kpk가 failure인 경우):

      1. store에 키 생성기가 없으면 "DataError" DOMException을 던집니다.

      2. clone 및 store의 키 경로를 사용한 키를 값에 삽입할 수 있는지 확인이 false를 반환하면 "DataError" DOMException을 던집니다.

  12. operation을 store, clone, key 및 no-overwrite flag와 함께 객체 저장소에 레코드를 저장하는 알고리즘으로 둡니다.

  13. handle 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

delete(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. transaction이 읽기 전용 트랜잭션이면 "ReadOnlyError" DOMException을 던집니다.

  6. range를 query 및 true를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  7. operation을 store 및 range와 함께 객체 저장소에서 레코드를 삭제하는 알고리즘으로 둡니다.

  8. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 삭제할 레코드를 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다.

참고: 키 또는 키 범위를 받는 다른 메서드와 달리 이 메서드는 null을 키로 제공하는 것을 허용하지 않습니다. 이는 작은 버그 하나로 객체 저장소 전체가 지워질 위험을 줄이기 위한 것입니다.

clear() 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. transaction이 읽기 전용 트랜잭션이면 "ReadOnlyError" DOMException을 던집니다.

  6. operation을 store와 함께 객체 저장소를 비우는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

다음 메서드들은 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = store . get(query)

query의 주어진 키 또는 키 범위와 일치하는 첫 번째 레코드의 값을 검색합니다.

성공하면 request의 result는 값이 되고, 일치하는 레코드가 없으면 undefined가 됩니다.

request = store . getKey(query)

query의 주어진 키 또는 키 범위와 일치하는 첫 번째 레코드의 키를 검색합니다.

성공하면 request의 result는 키가 되고, 일치하는 레코드가 없으면 undefined가 됩니다.

request = store . getAll(query [, count])
request = store . getAll({query, count, direction})

query의 주어진 키 또는 키 범위와 일치하는 레코드의 값을 검색합니다 (count가 주어지면 최대 count개). 첫 번째 count개의 값을 검색하려면 direction 옵션을 "next"로, 마지막 count개의 값을 반환하려면 "prev"로 설정합니다.

성공하면 request의 result는 값의 Array가 됩니다.

request = store . getAllKeys(query [, count])
request = store . getAllKeys({query, count, direction})

query의 주어진 키 또는 키 범위와 일치하는 레코드의 키를 검색합니다 (count가 주어지면 최대 count개). 첫 번째 count개의 키를 검색하려면 direction 옵션을 "next"로, 마지막 count개의 키를 반환하려면 "prev"로 설정합니다.

성공하면 request의 result는 키의 Array가 됩니다.

request = store . getAllRecords({query, count, direction})

레코드의 키와 값을 검색합니다.

query 옵션은 일치시킬 키 또는 키 범위를 지정합니다. count 옵션은 일치하는 레코드 수를 제한합니다. 첫 번째 count개의 레코드를 검색하려면 direction 옵션을 "next"로, 마지막 count개의 레코드를 반환하려면 "prev"로 설정합니다.

성공하면 request의 result는 각 멤버가 IDBRecord인 Array가 됩니다.

request = store . count(query)

query의 주어진 키 또는 키 범위와 일치하는 레코드의 수를 검색합니다.

성공하면 request의 result는 개수가 됩니다.

get(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query 및 true를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 현재 Realm 레코드, store 및 range와 함께 객체 저장소에서 값을 검색하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 검색할 레코드 값을 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. 범위가 지정되면 메서드는 해당 범위에서 처음 존재하는 값을 검색합니다.

참고: 이 메서드는 주어진 키를 가진 레코드가 존재하지 않는 경우와 레코드는 존재하지만 값이 undefined인 경우에 동일한 결과를 생성합니다. 두 상황을 구분해야 한다면 동일한 키와 함께 openCursor()를 사용할 수 있습니다. 레코드가 존재하면 값이 undefined인 커서를 반환하고, 그러한 레코드가 존재하지 않으면 커서를 반환하지 않습니다.

getKey(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query 및 true를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 store 및 range와 함께 객체 저장소에서 키를 검색하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 검색할 레코드 키를 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. 범위가 지정되면 메서드는 해당 범위에서 처음 존재하는 키를 검색합니다.

getAll(queryOrOptions, count) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "value", queryOrOptions, 그리고 주어진 경우 count와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

getAllKeys(queryOrOptions, count) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "key", queryOrOptions, 그리고 주어진 경우 count와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

getAllRecords(options) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "record", 그리고 options와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

count(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 store 및 range와 함께 범위의 레코드 수를 계산하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 개수를 셀 레코드를 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

다음 메서드들은 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = store . openCursor([query [, direction = "next"]])

query와 일치하는 레코드에 대해 direction 순서로 커서를 엽니다. query가 null이면 store의 모든 레코드가 일치합니다.

성공하면 request의 result는 첫 번째로 일치하는 레코드를 가리키는 IDBCursorWithValue가 되고, 일치하는 레코드가 없으면 null이 됩니다.

request = store . openKeyCursor([query [, direction = "next"]])

query와 일치하는 레코드에 대해 키 전용 플래그가 true로 설정된 커서를 direction 순서로 엽니다. query가 null이면 store의 모든 레코드가 일치합니다.

성공하면 request의 result는 첫 번째로 일치하는 레코드를 가리키는 IDBCursor가 되고, 일치하는 레코드가 없으면 null이 됩니다.

openCursor(query, direction) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. cursor를 새로운 커서로 두고, 그 소스 핸들을 this로, 위치를 undefined로, 방향을 direction으로, 값 획득 플래그를 false로, 키와 값을 undefined로, 범위를 range로, 그리고 키 전용 플래그를 false로 설정합니다.

  7. operation을 현재 Realm 레코드 및 cursor와 함께 커서를 반복하는 알고리즘으로 둡니다.

  8. request를 this 및 operation과 함께 요청을 비동기적으로 실행한 결과로 둡니다.

  9. cursor의 요청을 request로 설정합니다.

  10. request를 반환합니다.

참고: query 매개변수는 커서의 범위로 사용할 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

openKeyCursor(query, direction) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. cursor를 새로운 커서로 두고, 그 소스 핸들을 this로, 위치를 undefined로, 방향을 direction으로, 값 획득 플래그를 false로, 키와 값을 undefined로, 범위를 range로, 그리고 키 전용 플래그를 true로 설정합니다.

  7. operation을 현재 Realm 레코드 및 cursor와 함께 커서를 반복하는 알고리즘으로 둡니다.

  8. request를 this 및 operation과 함께 요청을 비동기적으로 실행한 결과로 둡니다.

  9. cursor의 요청을 request로 설정합니다.

  10. request를 반환합니다.

참고: query 매개변수는 커서의 범위로 사용할 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

index = store . index(name)

store에서 name이라는 이름의 인덱스에 대한 IDBIndex를 반환합니다.

index = store . createIndex(name, keyPath [, options])

주어진 name, keyPath 및 options로 store에 새로운 인덱스를 생성하고 새로운 IDBIndex를 반환합니다. keyPath와 options가 store에 이미 있는 데이터로 충족할 수 없는 제약 조건을 정의하면 업그레이드 트랜잭션이 "ConstraintError" DOMException과 함께 중단됩니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

store . deleteIndex(name)

store에서 주어진 name을 가진 인덱스를 삭제합니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

createIndex(name, keyPath, options) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. transaction이 업그레이드 트랜잭션이 아니면 "InvalidStateError" DOMException을 던집니다.

  4. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  5. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  6. store에 name이라는 이름의 인덱스가 이미 존재하면 "ConstraintError" DOMException을 던집니다.

  7. keyPath가 유효한 키 경로가 아니면 "SyntaxError" DOMException을 던집니다.

  8. unique를 options의 unique 멤버로 둡니다.

  9. multiEntry를 options의 multiEntry 멤버로 둡니다.

  10. keyPath가 시퀀스이고 multiEntry가 true이면 "InvalidAccessError" DOMException을 던집니다.

  11. index를 store의 새로운 인덱스로 둡니다. index의 이름을 name으로, 키 경로를 keyPath로, 고유 플래그를 unique로, 그리고 multiEntry 플래그를 multiEntry로 설정합니다.

  12. index를 this의 인덱스 집합에 추가합니다.

  13. index 및 this와 연결된 새로운 인덱스 핸들을 반환합니다.

이 메서드는 객체 저장소에 주어진 이름을 가진 새로운 인덱스를 생성하고 반환합니다. 이 메서드는 업그레이드 트랜잭션 내에서만 호출해야 한다는 점에 유의하세요.

생성하도록 요청된 인덱스에는 인덱스의 참조되는 객체 저장소에서 허용되는 데이터에 대한 제약 조건이 포함될 수 있습니다. 예를 들어 인덱스의 키 경로가 참조하는 값의 고유성을 요구할 수 있습니다. 참조되는 객체 저장소에 이미 이러한 제약 조건을 위반하는 데이터가 포함되어 있어도 createIndex() 구현이 예외를 던지거나 반환 값에 영향을 주어서는 안 됩니다. 구현은 여전히 IDBIndex 객체를 생성하고 반환해야 하며, createIndex() 호출에 사용된 업그레이드 트랜잭션을 중단하도록 데이터베이스 태스크를 큐에 추가해야 합니다.

이 메서드는 호출된 IDBObjectStore 인스턴스의 indexNames 속성을 동기적으로 수정합니다. 이 메서드는 IDBRequest 객체를 반환하지 않지만, 인덱스 생성 자체는 업그레이드 트랜잭션 내에서 비동기 요청으로 처리됩니다.

일부 구현에서는 createIndex 메서드가 반환된 후 인덱스를 생성하는 과정에서 비동기적으로 문제가 발생할 수 있습니다. 예를 들어 새로 생성된 인덱스에 대한 메타데이터가 데이터베이스에 비동기적으로 삽입되도록 큐에 추가되는 구현이나, 할당량 문제로 인해 구현이 사용자에게 권한을 요청해야 할 수 있는 경우입니다. 이러한 구현도 여전히 IDBIndex 객체를 생성하고 반환해야 하며, 구현이 인덱스 생성이 실패했다고 판단하면 적절한 오류를 사용하여 트랜잭션 중단 단계를 실행해야 합니다. 예를 들어 인덱스 생성이 할당량 문제로 실패했다면 QuotaExceededError를 오류로 사용해야 하며, 고유 플래그 제약 조건 때문에 인덱스를 생성할 수 없다면 "ConstraintError" DOMException을 오류로 사용해야 합니다.

인덱스의 비동기 생성은 다음 예에서 관찰할 수 있습니다.

const request1 = objectStore.put({name: "betty"}, 1);
const request2 = objectStore.put({name: "betty"}, 2);
const index = objectStore.createIndex("by_name", "name", {unique: true});

createIndex()가 호출되는 시점에는 어느 요청도 실행되지 않았습니다. 두 번째 요청이 실행되면 중복 이름이 생성됩니다. 인덱스 생성은 비동기 요청으로 간주되므로 인덱스의 고유성 제약 조건으로 인해 두 번째 요청이 실패하지는 않습니다. 대신 인덱스가 생성되고 제약 조건이 실패할 때 트랜잭션이 중단됩니다.

index(name) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 완료이면 "InvalidStateError" DOMException을 던집니다.

  5. index를 this의 인덱스 집합에 존재하는 경우 name이라는 이름의 인덱스로 두고, 그렇지 않으면 "NotFoundError" DOMException을 던집니다.

  6. index 및 this와 연결된 인덱스 핸들을 반환합니다.

참고: 동일한 IDBObjectStore 인스턴스에서 동일한 이름으로 이 메서드를 호출할 때마다 동일한 IDBIndex 인스턴스를 반환합니다.

참고: 반환되는 IDBIndex 인스턴스는 이 IDBObjectStore 인스턴스에 한정됩니다. 이 메서드를 같은 이름을 가진 다른 IDBObjectStore 인스턴스에서 호출하면 다른 IDBIndex 인스턴스가 반환됩니다.

deleteIndex(name) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. store를 this의 객체 저장소로 둡니다.

  3. transaction이 업그레이드 트랜잭션이 아니면 "InvalidStateError" DOMException을 던집니다.

  4. store가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  5. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  6. index를 store에 존재하는 경우 name이라는 이름의 인덱스로 두고, 그렇지 않으면 "NotFoundError" DOMException을 던집니다.

  7. this의 인덱스 집합에서 index를 제거합니다.

  8. index를 파기합니다.

이 메서드는 객체 저장소에서 주어진 이름을 가진 인덱스를 파기합니다. 이 메서드는 업그레이드 트랜잭션 내에서만 호출해야 한다는 점에 유의하세요.

이 메서드는 호출된 IDBObjectStore 인스턴스의 indexNames 속성을 동기적으로 수정합니다. 이 메서드는 IDBRequest 객체를 반환하지 않지만, 인덱스 파기 자체는 업그레이드 트랜잭션 내에서 비동기 요청으로 처리됩니다.

4.6. IDBIndex 인터페이스

IDBIndex 인터페이스는 인덱스 핸들을 나타냅니다.

[Exposed=(Window,Worker)]
interface IDBIndex {
  attribute DOMString name;
  [SameObject] readonly attribute IDBObjectStore objectStore;
  readonly attribute any keyPath;
  readonly attribute boolean multiEntry;
  readonly attribute boolean unique;

  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any queryOrOptions,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");
};
index . name

인덱스의 이름을 반환합니다.

index . name = newName

저장소의 이름을 newName으로 갱신합니다.

업그레이드 트랜잭션 내에서 호출되지 않은 경우 "InvalidStateError" DOMException을 던집니다.

index . objectStore

인덱스가 속한 IDBObjectStore를 반환합니다.

index . keyPath

인덱스의 키 경로를 반환합니다.

index . multiEntry

인덱스의 multiEntry 플래그가 true이면 true를 반환합니다.

index . unique

인덱스의 고유 플래그가 true이면 true를 반환합니다.

name getter 단계는 this의 이름을 반환하는 것입니다.

이것은 인덱스의 이름과 같나요? 트랜잭션이 완료되지 않은 동안에는 연결된 인덱스의 이름과 같습니다. 그러나 트랜잭션이 완료되면 이 속성에는 이후 업그레이드 트랜잭션에서 이루어진 변경이 반영되지 않습니다.

name setter 단계는 다음과 같습니다.

  1. name을 주어진 값으로 둡니다.

  2. transaction을 this의 트랜잭션으로 둡니다.

  3. index를 this의 인덱스로 둡니다.

  4. transaction이 업그레이드 트랜잭션이 아니면 "InvalidStateError" DOMException을 던집니다.

  5. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  6. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  7. index의 이름이 name과 같으면 이 단계를 종료합니다.

  8. index의 객체 저장소에 name이라는 이름의 인덱스가 이미 존재하면 "ConstraintError" DOMException을 던집니다.

  9. index의 이름을 name으로 설정합니다.

  10. this의 이름을 name으로 설정합니다.

objectStore getter 단계는 this의 객체 저장소 핸들을 반환하는 것입니다.

keyPath getter 단계는 this의 인덱스의 키 경로를 반환하는 것입니다. 키 경로는 문자열인 경우 DOMString으로, 문자열 목록인 경우 sequence<DOMString>으로 [WEBIDL]에 따라 변환됩니다.

참고: 반환된 값은 인덱스가 생성될 때 사용된 것과 동일한 인스턴스가 아닙니다. 그러나 이 속성이 객체(구체적으로 Array)를 반환하는 경우에는 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 객체의 속성을 변경해도 인덱스에는 영향을 주지 않습니다.

multiEntry getter 단계는 this의 인덱스의 multiEntry 플래그를 반환하는 것입니다.

unique getter 단계는 this의 인덱스의 고유 플래그를 반환하는 것입니다.

다음 메서드들은 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = index . get(query)

query의 주어진 키 또는 키 범위와 일치하는 첫 번째 레코드의 값을 검색합니다.

성공하면 request의 result는 값이 되고, 일치하는 레코드가 없으면 undefined가 됩니다.

request = index . getKey(query)

query의 주어진 키 또는 키 범위와 일치하는 첫 번째 레코드의 키를 검색합니다.

성공하면 request의 result는 키가 되고, 일치하는 레코드가 없으면 undefined가 됩니다.

request = index . getAll(query [, count])
request = index . getAll({query, count, direction})

query의 주어진 키 또는 키 범위와 일치하는 레코드의 값을 검색합니다 (count가 주어지면 최대 count개). 첫 번째 count개의 값을 검색하려면 direction 옵션을 "next"로, 마지막 count개의 값을 반환하려면 "prev"로 설정합니다. 중복된 인덱스 키를 가진 첫 번째 레코드를 검색한 후 같은 인덱스 키를 가진 레코드를 제외하려면 direction 옵션을 "nextunique" 또는 "prevunique"로 설정합니다.

성공하면 request의 result는 값의 Array가 됩니다.

request = index . getAllKeys(query [, count])
request = index . getAllKeys({query, count, direction})

query의 주어진 키 또는 키 범위와 일치하는 레코드의 키를 검색합니다 (count가 주어지면 최대 count개). 첫 번째 count개의 키를 검색하려면 direction 옵션을 "next"로, 마지막 count개의 키를 반환하려면 "prev"로 설정합니다. 중복된 인덱스 키를 가진 첫 번째 레코드를 검색한 후 같은 인덱스 키를 가진 레코드를 제외하려면 direction 옵션을 "nextunique" 또는 "prevunique"로 설정합니다.

성공하면 request의 result는 키의 Array가 됩니다.

request = index . getAllRecords({query, count, direction})

레코드의 키, 값, 그리고 인덱스 키를 검색합니다.

query 옵션은 일치시킬 키 또는 키 범위를 지정합니다. count 옵션은 일치하는 레코드 수를 제한합니다. 첫 번째 count개의 레코드를 검색하려면 direction 옵션을 "next"로, 마지막 count개의 레코드를 반환하려면 "prev"로 설정합니다. 중복된 인덱스 키를 가진 첫 번째 레코드를 검색한 후 같은 인덱스 키를 가진 레코드를 제외하려면 direction 옵션을 "nextunique" 또는 "prevunique"로 설정합니다.

성공하면 request의 result는 각 멤버가 IDBRecord인 Array가 됩니다. 레코드의 인덱스 키를 얻으려면 IDBRecord의 key를 사용합니다. 레코드의 키를 얻으려면 IDBRecord의 primaryKey를 사용합니다.

request = index . count(query)

query의 주어진 키 또는 키 범위와 일치하는 레코드의 수를 검색합니다.

성공하면 request의 result는 개수가 됩니다.

get(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. index를 this의 인덱스로 둡니다.

  3. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query 및 true를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 현재 Realm 레코드, index, 그리고 range와 함께 인덱스에서 참조된 값을 검색하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 검색할 참조된 값을 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. 범위가 지정되면 메서드는 해당 범위에서 처음 존재하는 레코드를 검색합니다.

참고: 이 메서드는 주어진 키를 가진 레코드가 존재하지 않는 경우와 레코드는 존재하지만 값이 undefined인 경우에 동일한 결과를 생성합니다. 두 상황을 구분해야 한다면 동일한 키와 함께 openCursor()를 사용할 수 있습니다. 레코드가 존재하면 값이 undefined인 커서를 반환하고, 그러한 레코드가 존재하지 않으면 커서를 반환하지 않습니다.

getKey(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. index를 this의 인덱스로 둡니다.

  3. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query 및 true를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 index 및 range와 함께 인덱스에서 값을 검색하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 검색할 레코드 키를 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. 범위가 지정되면 메서드는 해당 범위에서 처음 존재하는 키를 검색합니다.

getAll(queryOrOptions, count) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "value", queryOrOptions, 그리고 주어진 경우 count와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

getAllKeys(queryOrOptions, count) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "key", queryOrOptions, 그리고 주어진 경우 count와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

getAllRecords(options) 메서드 단계는 다음과 같습니다.

  1. 현재 Realm 레코드, this, "record", 그리고 options와 함께 여러 항목을 검색하기 위한 요청을 생성한 결과를 반환합니다. 모든 예외를 다시 던집니다.

count(query) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. index를 this의 인덱스로 둡니다.

  3. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. operation을 index 및 range와 함께 범위의 레코드 수를 계산하는 알고리즘으로 둡니다.

  7. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 개수를 셀 레코드를 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

다음 메서드들은 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = index . openCursor([query [, direction = "next"]])

query와 일치하는 레코드에 대해 direction 순서로 커서를 엽니다. query가 null이면 index의 모든 레코드가 일치합니다.

성공하면 request의 result는 IDBCursorWithValue가 되고, 일치하는 레코드가 없으면 null이 됩니다.

request = index . openKeyCursor([query [, direction = "next"]])

query와 일치하는 레코드에 대해 키 전용 플래그가 true로 설정된 커서를 direction 순서로 엽니다. query가 null이면 index의 모든 레코드가 일치합니다.

성공하면 request의 result는 IDBCursor가 되고, 일치하는 레코드가 없으면 null이 됩니다.

openCursor(query, direction) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. index를 this의 인덱스로 둡니다.

  3. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. cursor를 새로운 커서로 두고, 그 소스 핸들을 this로, 위치를 undefined로, 방향을 direction으로, 값 획득 플래그를 false로, 키와 값을 undefined로, 범위를 range로, 그리고 키 전용 플래그를 false로 설정합니다.

  7. operation을 현재 Realm 레코드 및 cursor와 함께 커서를 반복하는 알고리즘으로 둡니다.

  8. request를 this 및 operation과 함께 요청을 비동기적으로 실행한 결과로 둡니다.

  9. cursor의 요청을 request로 설정합니다.

  10. request를 반환합니다.

참고: query 매개변수는 커서의 범위로 사용할 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

openKeyCursor(query, direction) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. index를 this의 인덱스로 둡니다.

  3. index 또는 index의 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  5. range를 query를 사용하여 값을 키 범위로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  6. cursor를 새로운 커서로 두고, 그 소스 핸들을 this로, 위치를 undefined로, 방향을 direction으로, 값 획득 플래그를 false로, 키와 값을 undefined로, 범위를 range로, 그리고 키 전용 플래그를 true로 설정합니다.

  7. operation을 현재 Realm 레코드 및 cursor와 함께 커서를 반복하는 알고리즘으로 둡니다.

  8. request를 this 및 operation과 함께 요청을 비동기적으로 실행한 결과로 둡니다.

  9. cursor의 요청을 request로 설정합니다.

  10. request를 반환합니다.

참고: query 매개변수는 커서의 범위로 사용할 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다.

4.7. IDBKeyRange 인터페이스

IDBKeyRange 인터페이스는 키 범위를 나타냅니다.

[Exposed=(Window,Worker)]
interface IDBKeyRange {
  readonly attribute any lower;
  readonly attribute any upper;
  readonly attribute boolean lowerOpen;
  readonly attribute boolean upperOpen;

  // 정적 생성 메서드:
  [NewObject] static IDBKeyRange only(any value);
  [NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false);
  [NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false);
  [NewObject] static IDBKeyRange bound(any lower,
                                       any upper,
                                       optional boolean lowerOpen = false,
                                       optional boolean upperOpen = false);

  boolean includes(any key);
};
range . lower

범위의 하한을 반환하고, 없으면 undefined를 반환합니다.

range . upper

범위의 상한을 반환하고, 없으면 undefined를 반환합니다.

range . lowerOpen

범위의 하한 개방 플래그를 반환합니다.

range . upperOpen

범위의 상한 개방 플래그를 반환합니다.

lower getter 단계는 this의 하한이 null이 아니면 이를 사용하여 키를 값으로 변환한 결과를 반환하고, 그렇지 않으면 undefined를 반환하는 것입니다.

upper getter 단계는 this의 상한이 null이 아니면 이를 사용하여 키를 값으로 변환한 결과를 반환하고, 그렇지 않으면 undefined를 반환하는 것입니다.

lowerOpen getter 단계는 this의 하한 개방 플래그를 반환하는 것입니다.

upperOpen getter 단계는 this의 상한 개방 플래그를 반환하는 것입니다.

range = IDBKeyRange . only(key)

key만 포함하는 새로운 IDBKeyRange를 반환합니다.

range = IDBKeyRange . lowerBound(key [, open = false])

key에서 시작하고 상한이 없는 새로운 IDBKeyRange를 반환합니다. open이 true이면 key는 범위에 포함되지 않습니다.

range = IDBKeyRange . upperBound(key [, open = false])

하한이 없고 key에서 끝나는 새로운 IDBKeyRange를 반환합니다. open이 true이면 key는 범위에 포함되지 않습니다.

range = IDBKeyRange . bound(lower, upper [, lowerOpen = false [, upperOpen = false]])

lower에서 upper까지의 새로운 IDBKeyRange를 반환합니다. lowerOpen이 true이면 lower는 범위에 포함되지 않습니다. upperOpen이 true이면 upper는 범위에 포함되지 않습니다.

only(value) 메서드 단계는 다음과 같습니다.

  1. key를 value를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. key가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  3. key만 포함하는 새로운 키 범위를 생성하고 반환합니다.

lowerBound(lower, open) 메서드 단계는 다음과 같습니다.

  1. lowerKey를 lower를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. lowerKey가 유효하지 않으면 "DataError" DOMException을 던집니다.

  3. 하한을 lowerKey로, 하한 개방 플래그를 open으로, 상한을 null로, 그리고 상한 개방 플래그를 true로 설정한 새로운 키 범위를 생성하고 반환합니다.

upperBound(upper, open) 메서드 단계는 다음과 같습니다.

  1. upperKey를 upper를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. upperKey가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  3. 하한을 null로, 하한 개방 플래그를 true로, 상한을 upperKey로, 그리고 상한 개방 플래그를 open으로 설정한 새로운 키 범위를 생성하고 반환합니다.

bound(lower, upper, lowerOpen, upperOpen) 메서드 단계는 다음과 같습니다.

  1. lowerKey를 lower를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. lowerKey가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  3. upperKey를 upper를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  4. upperKey가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  5. lowerKey가 upperKey보다 크면 "DataError" DOMException을 던집니다.

  6. 하한을 lowerKey로, 하한 개방 플래그를 lowerOpen으로, 상한을 upperKey로, 그리고 상한 개방 플래그를 upperOpen으로 설정한 새로운 키 범위를 생성하고 반환합니다.

range . includes(key)

key가 범위에 포함되면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

includes(key) 메서드 단계는 다음과 같습니다.

  1. k를 key를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. k가 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  3. k가 이 범위 안에 있으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

4.8. IDBRecord 인터페이스

IDBRecord 인터페이스는 레코드 스냅샷을 나타냅니다.

[Exposed=(Window,Worker)]
interface IDBRecord {
  readonly attribute any key;
  readonly attribute any primaryKey;
  readonly attribute any value;
};
record . key

레코드의 키를 반환합니다.

record . primaryKey

레코드를 인덱스에서 검색한 경우, 인덱스의 참조되는 객체 저장소에 있는 레코드의 키를 반환합니다.

레코드를 객체 저장소에서 검색한 경우, 레코드의 키를 반환하며, 이는 record.key와 동일한 키입니다.

record . value

레코드의 값을 반환합니다.

key getter 단계는 this의 키를 사용하여 키를 값으로 변환한 결과를 반환하는 것입니다.

primaryKey getter 단계는 this의 기본 키를 사용하여 키를 값으로 변환한 결과를 반환하는 것입니다.

value getter 단계는 this의 값을 반환하는 것입니다.

4.9. IDBCursor 인터페이스

커서 객체는 IDBCursor 인터페이스를 구현합니다. 주어진 커서를 나타내는 IDBCursor 인스턴스는 항상 하나뿐입니다. 동시에 사용할 수 있는 커서 수에는 제한이 없습니다.

[Exposed=(Window,Worker)]
interface IDBCursor {
  readonly attribute (IDBObjectStore or IDBIndex) source;
  readonly attribute IDBCursorDirection direction;
  readonly attribute any key;
  readonly attribute any primaryKey;
  [SameObject] readonly attribute IDBRequest request;

  undefined advance([EnforceRange] unsigned long count);
  undefined continue(optional any key);
  undefined continuePrimaryKey(any key, any primaryKey);

  [NewObject] IDBRequest update(any value);
  [NewObject] IDBRequest delete();
};

enum IDBCursorDirection {
  "next",
  "nextunique",
  "prev",
  "prevunique"
};
cursor . source

커서가 열린 IDBObjectStore 또는 IDBIndex를 반환합니다.

cursor . direction

커서의 방향 ("next", "nextunique", "prev" 또는 "prevunique")을 반환합니다.

cursor . key

커서의 키를 반환합니다. 커서가 진행 중이거나 완료된 경우 "InvalidStateError" DOMException을 던집니다.

cursor . primaryKey

커서의 유효 키를 반환합니다. 커서가 진행 중이거나 완료된 경우 "InvalidStateError" DOMException을 던집니다.

cursor . request

이 커서를 얻는 데 사용된 요청을 반환합니다.

source getter 단계는 this의 소스 핸들을 반환하는 것입니다.

참고: source 속성은 커서가 현재 반복 중이거나, 끝을 지나 반복되었거나, 그 트랜잭션이 활성 상태가 아니더라도 null을 반환하거나 예외를 던지지 않습니다.

direction getter 단계는 this의 방향을 반환하는 것입니다.

key getter 단계는 커서의 현재 키를 사용하여 키를 값으로 변환한 결과를 반환하는 것입니다.

참고: key가 객체(예: Date 또는 Array)를 반환하면 커서의 키가 변경될 때까지 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 이는 객체가 수정되면 커서의 값을 검사하는 모든 사람이 그 수정 사항을 보게 됨을 의미합니다. 그러나 이러한 객체를 수정해도 데이터베이스의 내용은 수정되지 않습니다.

primaryKey getter 단계는 커서의 현재 유효 키를 사용하여 키를 값으로 변환한 결과를 반환하는 것입니다.

참고: primaryKey가 객체(예: Date 또는 Array)를 반환하면 커서의 유효 키가 변경될 때까지 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 이는 객체가 수정되면 커서의 값을 검사하는 모든 사람이 그 수정 사항을 보게 됨을 의미합니다. 그러나 이러한 객체를 수정해도 데이터베이스의 내용은 수정되지 않습니다.

request getter 단계는 this의 요청을 반환하는 것입니다.

🚧 request 속성은 이 판에서 새로 추가되었습니다. Chrome 76, Edge 79, Firefox 77 및 Safari 15에서 지원됩니다. 🚧
다음 메서드들은 커서를 진행시킵니다. 커서가 진행되면 커서를 열 때 반환된 동일한 IDBRequest에서 success 이벤트가 발생합니다. result는 범위 내에 레코드가 있으면 동일한 커서가 되고, 그렇지 않으면 undefined가 됩니다.

커서가 이미 진행 중일 때 호출되면 "InvalidStateError" DOMException을 던집니다.

다음 메서드들은 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.

cursor . advance(count)

범위 내의 다음 count개 레코드를 지나도록 커서를 진행시킵니다.

cursor . continue()

커서를 범위 내의 다음 레코드로 진행시킵니다.

cursor . continue(key)

커서를 범위 내에서 key와 일치하거나 그 이후에 있는 다음 레코드로 진행시킵니다.

cursor . continuePrimaryKey(key, primaryKey)

커서를 범위 내에서 key 및 primaryKey와 일치하거나 그 이후에 있는 다음 레코드로 진행시킵니다. 소스가 인덱스가 아니면 "InvalidAccessError" DOMException을 던집니다.

advance(count) 메서드 단계는 다음과 같습니다.

  1. count가 0(영)이면 TypeError를 던집니다.

  2. transaction을 this의 트랜잭션으로 둡니다.

  3. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  4. this의 소스 또는 유효 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  5. this의 값 획득 플래그가 false이면, 이는 커서가 반복 중이거나 끝을 지나 반복되었음을 나타내므로 "InvalidStateError" DOMException을 던집니다.

  6. this의 값 획득 플래그를 false로 설정합니다.

  7. request를 this의 요청으로 둡니다.

  8. request의 처리됨 플래그를 false로 설정합니다.

  9. request의 완료 플래그를 false로 설정합니다.

  10. operation을 현재 Realm 레코드, this, 그리고 count와 함께 커서를 반복하는 알고리즘으로 둡니다.

  11. this의 소스 핸들, operation, 그리고 request와 함께 요청을 비동기적으로 실행합니다.

참고: 새 커서 데이터가 로드되기 전에 이 메서드를 두 번 이상 호출하면 — 예를 들어 같은 onsuccess 핸들러에서 advance()를 두 번 호출하면 — 커서의 값 획득 플래그가 false로 설정되었으므로 두 번째 호출에서 "InvalidStateError" DOMException이 발생합니다.

continue(key) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  3. this의 소스 또는 유효 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. this의 값 획득 플래그가 false이면, 이는 커서가 반복 중이거나 끝을 지나 반복되었음을 나타내므로 "InvalidStateError" DOMException을 던집니다.

  5. key가 주어졌으면 다음을 수행합니다.

    1. r을 key를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

    2. r이 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

    3. key를 r로 둡니다.

    4. key가 this의 위치보다 작거나 같고, this의 방향이 "next" 또는 "nextunique"이면 "DataError" DOMException을 던집니다.

    5. key가 this의 위치보다 크거나 같고, this의 방향이 "prev" 또는 "prevunique"이면 "DataError" DOMException을 던집니다.

  6. this의 값 획득 플래그를 false로 설정합니다.

  7. request를 this의 요청으로 둡니다.

  8. request의 처리됨 플래그를 false로 설정합니다.

  9. request의 완료 플래그를 false로 설정합니다.

  10. operation을 현재 Realm 레코드, this, 그리고 key(주어진 경우)와 함께 커서를 반복하는 알고리즘으로 둡니다.

  11. this의 소스 핸들, operation, 그리고 request와 함께 요청을 비동기적으로 실행합니다.

참고: 새 커서 데이터가 로드되기 전에 이 메서드를 두 번 이상 호출하면 — 예를 들어 같은 onsuccess 핸들러에서 continue()를 두 번 호출하면 — 커서의 값 획득 플래그가 false로 설정되었으므로 두 번째 호출에서 "InvalidStateError" DOMException이 발생합니다.

continuePrimaryKey(key, primaryKey) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  3. this의 소스 또는 유효 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  4. this의 소스가 인덱스가 아니면 "InvalidAccessError" DOMException을 던집니다.

  5. this의 방향이 "next" 또는 "prev"가 아니면 "InvalidAccessError" DOMException을 던집니다.

  6. this의 값 획득 플래그가 false이면, 이는 커서가 반복 중이거나 끝을 지나 반복되었음을 나타내므로 "InvalidStateError" DOMException을 던집니다.

  7. r을 key를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  8. r이 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  9. key를 r로 둡니다.

  10. r을 primaryKey를 사용하여 값을 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  11. r이 "invalid value" 또는 "invalid type"이면 "DataError" DOMException을 던집니다.

  12. primaryKey를 r로 둡니다.

  13. key가 this의 위치보다 작고, this의 방향이 "next"이면 "DataError" DOMException을 던집니다.

  14. key가 this의 위치보다 크고, this의 방향이 "prev"이면 "DataError" DOMException을 던집니다.

  15. key가 this의 위치와 같고, primaryKey가 this의 객체 저장소 위치보다 작거나 같고, this의 방향이 "next"이면 "DataError" DOMException을 던집니다.

  16. key가 this의 위치와 같고, primaryKey가 this의 객체 저장소 위치보다 크거나 같고, this의 방향이 "prev"이면 "DataError" DOMException을 던집니다.

  17. this의 값 획득 플래그를 false로 설정합니다.

  18. request를 this의 요청으로 둡니다.

  19. request의 처리됨 플래그를 false로 설정합니다.

  20. request의 완료 플래그를 false로 설정합니다.

  21. operation을 현재 Realm 레코드, this, key, 그리고 primaryKey와 함께 커서를 반복하는 알고리즘으로 둡니다.

  22. this의 소스 핸들, operation, 그리고 request와 함께 요청을 비동기적으로 실행합니다.

참고: 새 커서 데이터가 로드되기 전에 이 메서드를 두 번 이상 호출하면 — 예를 들어 같은 onsuccess 핸들러에서 continuePrimaryKey()를 두 번 호출하면 — 커서의 값 획득 플래그가 false로 설정되었으므로 두 번째 호출에서 "InvalidStateError" DOMException이 발생합니다.

다음 메서드들은 읽기 전용 트랜잭션 내에서 호출되면 "ReadOnlyError" DOMException을 던지고, 트랜잭션이 활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 던집니다.
request = cursor . update(value)

커서가 가리키는 레코드를 새 값으로 갱신합니다.

유효 객체 저장소가 인라인 키를 사용하고 키가 변경되는 경우 "DataError" DOMException을 던집니다.

성공하면 request의 result는 레코드의 키가 됩니다.

request = cursor . delete()

커서가 가리키는 레코드를 삭제합니다.

성공하면 request의 result는 undefined가 됩니다.

update(value) 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  3. transaction이 읽기 전용 트랜잭션이면 "ReadOnlyError" DOMException을 던집니다.

  4. this의 소스 또는 유효 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  5. this의 값 획득 플래그가 false이면, 이는 커서가 반복 중이거나 끝을 지나 반복되었음을 나타내므로 "InvalidStateError" DOMException을 던집니다.

  6. this의 키 전용 플래그가 true이면 "InvalidStateError" DOMException을 던집니다.

  7. targetRealm을 사용자 에이전트가 정의한 Realm으로 둡니다.

  8. clone을 transaction 동안 targetRealm에서 value을 복제한 것으로 둡니다. 모든 예외를 다시 던집니다.

    왜 값의 복사본을 생성하나요? 값은 저장될 때 직렬화됩니다. 여기에서 이를 복사본으로 취급하면 이 명세의 다른 알고리즘이 이를 ECMAScript 값으로 취급할 수 있지만, 동작 차이를 관찰할 수 없는 경우 구현은 이를 최적화할 수 있습니다.
  9. this의 유효 객체 저장소가 인라인 키를 사용하면 다음을 수행합니다.

    1. kpk를 clone 및 this의 유효 객체 저장소의 키 경로를 사용하여 키 경로를 사용하여 값에서 키를 추출한 결과로 둡니다. 모든 예외를 다시 던집니다.

    2. kpk가 failure이거나, 유효하지 않거나, this의 유효 키와 같지 않으면 "DataError" DOMException을 던집니다.

  10. operation을 this의 유효 객체 저장소, clone, this의 유효 키, 그리고 false와 함께 객체 저장소에 레코드를 저장하는 알고리즘으로 둡니다.

  11. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: 객체 저장소에 레코드를 저장한 결과, 커서가 해당 레코드로 이동한 이후 레코드가 삭제되었다면 새 레코드가 생성됩니다.

delete() 메서드 단계는 다음과 같습니다.

  1. transaction을 this의 트랜잭션으로 둡니다.

  2. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  3. transaction이 읽기 전용 트랜잭션이면 "ReadOnlyError" DOMException을 던집니다.

  4. this의 소스 또는 유효 객체 저장소가 삭제된 경우 "InvalidStateError" DOMException을 던집니다.

  5. this의 값 획득 플래그가 false이면, 이는 커서가 반복 중이거나 끝을 지나 반복되었음을 나타내므로 "InvalidStateError" DOMException을 던집니다.

  6. this의 키 전용 플래그가 true이면 "InvalidStateError" DOMException을 던집니다.

  7. operation을 this의 유효 객체 저장소 및 this의 유효 키와 함께 객체 저장소에서 레코드를 삭제하는 알고리즘으로 둡니다.

  8. this 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

커서의 키 전용 플래그가 false로 설정되어 있으면 IDBCursorWithValue 인터페이스도 구현합니다.

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};
cursor . value

커서의 현재 값을 반환합니다.

value getter 단계는 this의 현재 값을 반환하는 것입니다.

참고: value가 객체를 반환하면 커서의 값이 변경될 때까지 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 이는 객체가 수정되면 커서의 값을 검사하는 모든 사람이 그 수정 사항을 보게 됨을 의미합니다. 그러나 이러한 객체를 수정해도 데이터베이스의 내용은 수정되지 않습니다.

4.10. IDBTransaction 인터페이스

트랜잭션 객체는 다음 인터페이스를 구현합니다.

[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
  readonly attribute DOMStringList objectStoreNames;
  readonly attribute IDBTransactionMode mode;
  readonly attribute IDBTransactionDurability durability;
  [SameObject] readonly attribute IDBDatabase db;
  readonly attribute DOMException? error;

  IDBObjectStore objectStore(DOMString name);
  undefined commit();
  undefined abort();

  // 이벤트 핸들러:
  attribute EventHandler onabort;
  attribute EventHandler oncomplete;
  attribute EventHandler onerror;
};

enum IDBTransactionMode {
  "readonly",
  "readwrite",
  "versionchange"
};
transaction . objectStoreNames

트랜잭션의 범위에 있는 객체 저장소의 이름 목록을 반환합니다. 업그레이드 트랜잭션의 경우 이는 데이터베이스의 모든 객체 저장소입니다.

transaction . mode

트랜잭션이 생성될 때 사용된 모드 ("readonly" 또는 "readwrite")를 반환하거나, 업그레이드 트랜잭션의 경우 "versionchange"를 반환합니다.

transaction . durability

트랜잭션이 생성될 때 사용된 내구성 힌트 ("strict", "relaxed") 또는 "default"를 반환합니다.

transaction . db

트랜잭션의 연결을 반환합니다.

transaction . error

트랜잭션이 중단되었다면, 그 이유를 제공하는 오류(DOMException)를 반환합니다.

objectStoreNames getter 단계는 다음과 같습니다.

  1. names를 this의 범위에 있는 객체 저장소의 이름의 목록으로 둡니다.

  2. names를 사용하여 정렬된 이름 목록을 생성한 결과(DOMStringList)를 반환합니다.

참고: 이 속성이 반환하는 각 목록의 내용은 변경되지 않지만, 업그레이드 트랜잭션 중 이 속성을 이후에 호출하면 객체 저장소가 생성되고 삭제됨에 따라 내용이 다른 목록을 반환할 수 있습니다.

mode getter 단계는 this의 모드를 반환하는 것입니다.

durability getter 단계는 this의 내구성 힌트를 반환하는 것입니다.

🚧 durability 속성은 이 판에서 새로 추가되었습니다. Chrome 82, Edge 82, Firefox 126 및 Safari 15에서 지원됩니다. 🚧

db getter 단계는 this의 연결과 연결된 데이터베이스를 반환하는 것입니다.

error getter 단계는 this의 오류를 반환하고, 없으면 null을 반환하는 것입니다.

참고: 이 트랜잭션이 실패한 요청 때문에 중단되었다면 이는 요청의 오류와 동일합니다. 이 트랜잭션이 이벤트 핸들러에서 잡히지 않은 예외 때문에 중단되었다면 오류는 "AbortError" DOMException이 됩니다. 트랜잭션이 커밋 중 오류로 인해 중단되었다면 실패 이유(예: QuotaExceededError, 또는 "ConstraintError" 또는 "UnknownError" DOMException)를 반영합니다.

transaction . objectStore(name)

트랜잭션의 범위에 있는 IDBObjectStore를 반환합니다.

transaction . abort()

트랜잭션을 중단합니다. 보류 중인 모든 요청은 "AbortError" DOMException과 함께 실패하고 데이터베이스에 적용된 모든 변경 사항이 되돌려집니다.

transaction . commit()

트랜잭션을 커밋하려고 시도합니다. 보류 중인 모든 요청은 완료될 수 있지만, 새로운 요청은 허용되지 않습니다. 이는 정상적으로 커밋을 시도하기 전에 보류 중인 요청이 success 이벤트를 발생시키기를 기다리지 않고 트랜잭션을 빠르게 완료하도록 강제하는 데 사용할 수 있습니다.

보류 중인 요청이 예를 들어 제약 조건 오류 때문에 실패하면 트랜잭션은 중단됩니다. 성공한 요청의 success 이벤트는 여전히 발생하지만, 이벤트 핸들러에서 예외를 던져도 트랜잭션이 중단되지는 않습니다. 마찬가지로 실패한 요청의 error 이벤트도 여전히 발생하지만, preventDefault()를 호출해도 트랜잭션이 중단되는 것을 막지는 못합니다.

objectStore(name) 메서드 단계는 다음과 같습니다.

  1. this의 상태가 완료이면 "InvalidStateError" DOMException을 던집니다.

  2. store를 this의 범위에 있는 name이라는 이름의 객체 저장소로 두고, 그러한 저장소가 없으면 "NotFoundError" DOMException을 던집니다.

  3. store 및 this와 연결된 객체 저장소 핸들을 반환합니다.

참고: 동일한 IDBTransaction 인스턴스에서 같은 이름으로 이 메서드를 호출할 때마다 동일한 IDBObjectStore 인스턴스를 반환합니다.

참고: 반환되는 IDBObjectStore 인스턴스는 이 IDBTransaction에 한정됩니다. 이 메서드를 다른 IDBTransaction에서 호출하면 다른 IDBObjectStore 인스턴스가 반환됩니다.

abort() 메서드 단계는 다음과 같습니다.

  1. this의 상태가 커밋 중 또는 완료이면 "InvalidStateError" DOMException을 던집니다.

  2. this 및 null과 함께 트랜잭션을 중단합니다.

commit() 메서드 단계는 다음과 같습니다.

  1. this의 상태가 활성이 아니면 "InvalidStateError" DOMException을 던집니다.

  2. this와 함께 트랜잭션을 커밋합니다.

🚧 commit() 메서드는 이 판에서 새로 추가되었습니다. Chrome 76, Edge 79, Firefox 74 및 Safari 15에서 지원됩니다. 🚧

참고: 일반적으로 트랜잭션에서 commit()을 호출할 필요는 없습니다. 모든 미처리 요청이 충족되고 새로운 요청이 만들어지지 않으면 트랜잭션은 자동으로 커밋됩니다. 이 호출은 미처리 요청의 이벤트가 디스패치되기를 기다리지 않고 커밋 프로세스를 시작하는 데 사용할 수 있습니다.

onabort 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 abort입니다.

oncomplete 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 complete입니다.

onerror 속성은 이벤트 핸들러 IDL 속성이며, 그 이벤트 핸들러 이벤트 유형은 error입니다.

참고: 트랜잭션이 성공적으로 완료되었는지 확인하려면 특정 요청의 success 이벤트 대신 트랜잭션의 complete 이벤트를 수신하세요. 트랜잭션은 success 이벤트가 발생한 뒤에도 여전히 실패할 수 있기 때문입니다.

5. 알고리즘

5.1. 데이터베이스 연결 열기

데이터베이스를 열도록 요청한 storageKey, 데이터베이스 name, 데이터베이스 version 및 request로 데이터베이스 연결을 열려면 다음 단계를 실행합니다.

  1. queue를 storageKey 및 name에 대한 연결 큐로 둡니다.

  2. request를 queue에 추가합니다.

  3. queue의 이전 요청이 모두 처리될 때까지 기다립니다.

  4. db를 storageKey에 있는 name이라는 이름의 데이터베이스로 두고, 그렇지 않으면 null로 둡니다.

  5. version이 undefined이면, db가 null인 경우 version을 1로 두고, 그렇지 않으면 db의 버전으로 둡니다.

  6. db가 null이면, db를 새 데이터베이스로 두고 이름을 name으로, 버전을 0(영)으로 설정하며 객체 저장소는 없는 것으로 합니다. 어떤 이유로든 실패하면 적절한 오류(예: QuotaExceededError, 또는 "UnknownError" DOMException)를 반환합니다.

  7. db의 버전이 version보다 크면, 새로 생성된 "VersionError" DOMException을 반환하고 이 단계를 중단합니다.

  8. connection을 db에 대한 새로운 연결로 둡니다.

  9. connection의 버전을 version으로 설정합니다.

  10. db의 버전이 version보다 작으면 다음을 수행합니다.

    1. openConnections를 db와 연결된 모든 연결 중 connection을 제외한 집합으로 둡니다.

    2. openConnections의 각 entry 중 닫기 보류 플래그가 true로 설정되지 않은 항목에 대해 다음을 수행합니다. entry에서 db의 버전 및 version과 함께 versionchange라는 이름의 버전 변경 이벤트를 발생시키도록 데이터베이스 태스크를 큐에 추가합니다.

      참고: 이 이벤트를 발생시키면 openConnections의 다른 객체 중 하나 이상이 닫힐 수 있으며, 이 경우 아직 해당 객체에서 versionchange 이벤트를 발생시키지 않았더라도 해당 이벤트는 발생하지 않습니다.

    3. 모든 이벤트가 발생할 때까지 기다립니다.

    4. openConnections의 연결 중 여전히 닫히지 않은 것이 있으면 request에서 db의 버전 및 version과 함께 blocked라는 이름의 버전 변경 이벤트를 발생시키도록 데이터베이스 태스크를 큐에 추가합니다.

    5. openConnections의 모든 연결이 닫힐 때까지 기다립니다.

    6. connection, version 및 request를 사용하여 데이터베이스를 업그레이드합니다.

    7. connection이 닫혔다면, 새로 생성된 "AbortError" DOMException을 반환하고 이 단계를 중단합니다.

    8. request의 오류가 설정되어 있으면 connection으로 데이터베이스 연결을 닫는 단계를 실행하고, 새로 생성된 "AbortError" DOMException을 반환하고 이 단계를 중단합니다.

  11. connection을 반환합니다.

5.2. 데이터베이스 연결 닫기

connection 객체 및 선택적 forced flag로 데이터베이스 연결을 닫으려면 다음 단계를 실행합니다.

  1. connection의 닫기 보류 플래그를 true로 설정합니다.

  2. forced flag가 true이면, connection을 사용해 생성된 각 transaction에 대해 transaction 및 새로 생성된 "AbortError" DOMException과 함께 트랜잭션을 중단합니다.

  3. connection을 사용해 생성된 모든 트랜잭션이 완료될 때까지 기다립니다. 완료되면 connection은 닫힙니다.

  4. forced flag가 true이면 connection에서 close라는 이름의 이벤트를 발생시킵니다.

    참고: close 이벤트는 연결이 비정상적으로 닫힐 때만 발생합니다. 예를 들어 스토리지 키의 스토리지가 지워지거나 손상 또는 I/O 오류가 발생한 경우입니다. close()가 명시적으로 호출되면 이벤트는 발생하지 않습니다.

참고: 연결의 닫기 보류 플래그가 true로 설정되면 해당 연결을 사용하여 새로운 트랜잭션을 생성할 수 없습니다. 트랜잭션을 생성하는 모든 메서드는 먼저 연결의 닫기 보류 플래그를 확인하고 true이면 예외를 던집니다.

참고: 연결이 닫히면 데이터베이스를 업그레이드하는 단계와 데이터베이스를 삭제하는 단계의 차단이 해제될 수 있습니다. 이 두 단계는 계속 진행하기 전에 주어진 데이터베이스에 대한 연결이 닫히기를 둘 다 기다립니다.

5.3. 데이터베이스 삭제

데이터베이스 삭제를 요청한 storageKey, 데이터베이스 name 및 request로 데이터베이스를 삭제하려면 다음 단계를 실행합니다.

  1. queue를 storageKey 및 name에 대한 연결 큐로 둡니다.

  2. request를 queue에 추가합니다.

  3. queue의 이전 요청이 모두 처리될 때까지 기다립니다.

  4. db를 존재하는 경우 storageKey에 있는 name이라는 이름의 데이터베이스로 둡니다. 그렇지 않으면 0(영)을 반환합니다.

  5. openConnections를 db와 연결된 모든 연결의 집합으로 둡니다.

  6. openConnections의 각 entry 중 닫기 보류 플래그가 true로 설정되지 않은 항목에 대해 다음을 수행합니다. entry에서 db의 버전 및 null과 함께 versionchange라는 이름의 버전 변경 이벤트를 발생시키도록 데이터베이스 태스크를 큐에 추가합니다.

    참고: 이 이벤트를 발생시키면 openConnections의 다른 객체 중 하나 이상이 닫힐 수 있으며, 이 경우 아직 해당 객체에서 versionchange 이벤트를 발생시키지 않았더라도 해당 이벤트는 발생하지 않습니다.

  7. 모든 이벤트가 발생할 때까지 기다립니다.

  8. openConnections의 연결 중 여전히 닫히지 않은 것이 있으면 request에서 db의 버전 및 null과 함께 blocked라는 이름의 버전 변경 이벤트를 발생시키도록 데이터베이스 태스크를 큐에 추가합니다.

  9. openConnections의 모든 연결이 닫힐 때까지 기다립니다.

  10. version을 db의 버전으로 둡니다.

  11. db를 삭제합니다. 어떤 이유로든 실패하면 적절한 오류(예: QuotaExceededError, 또는 "UnknownError" DOMException)를 반환합니다.

  12. version을 반환합니다.

5.4. 트랜잭션 커밋

커밋할 transaction으로 트랜잭션을 커밋하려면 다음 단계를 실행합니다.

  1. transaction의 상태를 커밋 중으로 설정합니다.

  2. 다음 단계를 병렬로 실행합니다.

    1. transaction의 요청 목록의 모든 항목이 처리될 때까지 기다립니다.

    2. transaction의 상태가 더 이상 커밋 중이 아니면 이 단계를 종료합니다.

    3. transaction의 내구성 힌트를 고려하여 transaction이 데이터베이스에 적용한 미처리 변경 사항을 기록하려고 시도합니다.

    4. 데이터베이스에 변경 사항을 기록하는 중 오류가 발생하면 transaction 및 오류에 적절한 유형(예: QuotaExceededError 또는 "UnknownError" DOMException)과 함께 트랜잭션을 중단하고 이 단계를 종료합니다.

    5. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

      1. transaction이 업그레이드 트랜잭션이면, transaction의 연결과 연결된 데이터베이스의 업그레이드 트랜잭션을 null로 설정합니다.

      2. transaction의 상태를 완료로 설정합니다.

      3. transaction에서 complete라는 이름의 이벤트를 발생시킵니다.

        참고: 이 이벤트의 이벤트 핸들러 중 하나에서 예외가 발생하더라도 데이터베이스 변경 사항 기록은 이벤트보다 먼저 일어나므로 트랜잭션은 여전히 커밋됩니다. 트랜잭션이 성공적으로 기록된 후에만 complete 이벤트가 발생합니다.

      4. transaction이 업그레이드 트랜잭션이면, request를 transaction과 연결된 요청으로 두고 request의 트랜잭션을 null로 설정합니다.

5.5. 트랜잭션 중단

중단할 transaction 및 error로 트랜잭션을 중단하려면 다음 단계를 실행합니다.

  1. transaction의 상태가 완료이면 이 단계를 중단합니다.

  2. 트랜잭션이 데이터베이스에 적용한 모든 변경 사항을 되돌립니다. 업그레이드 트랜잭션의 경우 여기에는 객체 저장소 및 인덱스 집합의 변경뿐 아니라 버전 변경도 포함됩니다. 트랜잭션 중 생성된 모든 객체 저장소와 인덱스는 이제 다른 알고리즘에서 삭제된 것으로 간주됩니다.

  3. transaction이 업그레이드 트랜잭션이면, transaction과 함께 업그레이드 트랜잭션을 중단하는 단계를 실행합니다.

    참고: 이는 transaction과 연결된 모든 연결, 객체 저장소 핸들 및 인덱스 핸들 인스턴스의 변경 사항을 되돌립니다.

  4. transaction의 상태를 완료로 설정합니다.

  5. transaction의 오류를 error로 설정합니다.

  6. transaction의 요청 목록에 있는 각 request에 대해 다음을 수행합니다. request에 대한 요청을 비동기적으로 실행하는 단계를 중단하고, request의 처리됨 플래그를 true로 설정한 뒤 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

    1. request의 완료 플래그를 true로 설정합니다.

    2. request의 결과를 undefined로 설정합니다.

    3. request의 오류를 새로 생성된 "AbortError" DOMException으로 설정합니다.

    4. request에서 error라는 이름의 이벤트를 발생시키고 그 bubbles 및 cancelable 속성을 true로 초기화합니다.

    참고: 이것이 항상 error 이벤트 발생으로 이어지는 것은 아닙니다. 예를 들어 트랜잭션을 커밋 중 오류 때문에 트랜잭션이 중단되었거나, 실패한 요청이 마지막으로 남은 요청이었다면 그렇습니다.

  7. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

    1. transaction이 업그레이드 트랜잭션이면 transaction의 연결과 연결된 데이터베이스의 업그레이드 트랜잭션을 null로 설정합니다.

    2. transaction에서 abort라는 이름의 이벤트를 발생시키고 그 bubbles 속성을 true로 초기화합니다.

    3. transaction이 업그레이드 트랜잭션이면 다음을 수행합니다.

      1. request를 transaction과 연결된 열기 요청으로 둡니다.

      2. request의 트랜잭션을 null로 설정합니다.

      3. request의 결과를 undefined로 설정합니다.

      4. request의 처리됨 플래그를 false로 설정합니다.

      5. request의 완료 플래그를 false로 설정합니다.

5.6. 요청을 비동기적으로 실행

데이터베이스에서 수행할 operation과 source 객체 및 선택적 request로 요청을 비동기적으로 실행하려면 다음 단계를 실행합니다.

생성된 요청이 속한 트랜잭션이 트랜잭션을 중단하는 단계를 사용하여 중단되면 이 단계들은 어느 시점에서든 중단될 수 있습니다.

  1. transaction을 source와 연결된 트랜잭션으로 둡니다.

  2. 단언: transaction의 상태는 활성입니다.

  3. request가 주어지지 않았으면 request를 source를 소스로 하는 새로운 요청으로 둡니다.

  4. request를 transaction의 요청 목록의 끝에 추가합니다.

  5. 다음 단계를 병렬로 실행합니다.

    1. request가 transaction의 요청 목록에서 처리되지 않은 첫 번째 항목이 될 때까지 기다립니다.

    2. result를 operation을 수행한 결과로 둡니다.

    3. result가 오류이고 transaction의 상태가 커밋 중이면 transaction 및 result와 함께 트랜잭션을 중단하고 이 단계를 종료합니다.

    4. result가 오류이면 operation이 적용한 모든 변경 사항을 되돌립니다.

      참고: 이는 이 요청이 적용한 변경 사항만 되돌리며 트랜잭션이 적용한 다른 변경 사항은 되돌리지 않습니다.

    5. request의 처리됨 플래그를 true로 설정합니다.

    6. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

      1. request를 transaction의 요청 목록에서 제거합니다.

      2. request의 완료 플래그를 true로 설정합니다.

      3. result가 오류이면 다음을 수행합니다.

        1. request의 결과를 undefined로 설정합니다.

        2. request의 오류를 result로 설정합니다.

        3. request에서 오류 이벤트를 발생시킵니다.

      4. 그렇지 않으면 다음을 수행합니다.

        1. request의 결과를 result로 설정합니다.

        2. request의 오류를 undefined로 설정합니다.

        3. request에서 성공 이벤트를 발생시킵니다.

  6. request를 반환합니다.

5.7. 데이터베이스 업그레이드

connection(연결), 새로운 version 및 request로 데이터베이스를 업그레이드하려면 다음 단계를 실행합니다.

  1. db를 connection의 데이터베이스로 둡니다.

  2. transaction을 connection을 연결로 사용하는 새로운 업그레이드 트랜잭션으로 둡니다.

  3. transaction의 범위를 connection의 객체 저장소 집합으로 설정합니다.

  4. db의 업그레이드 트랜잭션을 transaction으로 설정합니다.

  5. transaction의 상태를 비활성으로 설정합니다.

  6. transaction을 시작합니다.

    참고: 이 트랜잭션이 완료될 때까지 동일한 데이터베이스에 다른 연결을 열 수 없다는 점에 유의하세요.

  7. old version을 db의 버전으로 둡니다.

  8. db의 버전을 version으로 설정합니다. 이 변경은 트랜잭션의 일부로 간주되므로, 트랜잭션이 중단되면 이 변경이 되돌려집니다.

  9. request의 처리됨 플래그를 true로 설정합니다.

  10. 다음 단계를 실행하도록 데이터베이스 태스크를 큐에 추가합니다.

    1. request의 결과를 connection으로 설정합니다.

    2. request의 트랜잭션을 transaction으로 설정합니다.

    3. request의 완료 플래그를 true로 설정합니다.

    4. transaction의 상태를 활성으로 설정합니다.

    5. didThrow를 request에서 old version 및 version과 함께 upgradeneeded라는 이름의 버전 변경 이벤트를 발생시킨 결과로 둡니다.

    6. transaction의 상태가 활성이면 다음을 수행합니다.

      1. transaction의 상태를 비활성으로 설정합니다.

      2. didThrow가 true이면 transaction 및 새로 생성된 "AbortError" DOMException과 함께 트랜잭션을 중단합니다.

  11. transaction이 완료될 때까지 기다립니다.

    참고: 트랜잭션의 수명 동안 호출되는 일부 알고리즘, 예를 들어 트랜잭션을 커밋하는 단계와 트랜잭션을 중단하는 단계에는 업그레이드 트랜잭션에 특화된 단계가 포함됩니다.

5.8. 업그레이드 트랜잭션 중단

transaction으로 업그레이드 트랜잭션을 중단하려면 다음 단계를 실행합니다.

참고: 이 단계들은 트랜잭션을 중단하는 단계에서 필요에 따라 실행되며, 이 단계는 연결된 객체 저장소와 인덱스 집합 및 버전 변경을 포함한 데이터베이스의 변경 사항을 되돌립니다.

  1. connection을 transaction의 연결로 둡니다.

  2. database를 connection의 데이터베이스로 둡니다.

  3. connection의 버전을 database가 이전에 존재했다면 database의 버전으로, database가 새로 생성되었다면 0(영)으로 설정합니다.

    참고: 이는 IDBDatabase 객체가 반환하는 version 값을 되돌립니다.

  4. connection의 객체 저장소 집합을 database가 이전에 존재했다면 database의 객체 저장소 집합으로, database가 새로 생성되었다면 빈 집합으로 설정합니다.

    참고: 이는 IDBDatabase 객체가 반환하는 objectStoreNames 값을 되돌립니다.

  5. transaction과 연결된 각 객체 저장소 핸들 handle에 대해, transaction 중 생성되거나 삭제된 객체 저장소의 핸들도 포함하여 다음을 수행합니다.

    1. handle의 객체 저장소가 transaction 중 새로 생성된 것이 아니면, handle의 이름을 해당 객체 저장소의 이름으로 설정합니다.

    2. handle의 인덱스 집합을 해당 객체 저장소를 참조하는 인덱스 집합으로 설정합니다.

    참고: 이는 관련 IDBObjectStore 객체가 반환하는 name 및 indexNames 값을 되돌립니다.

    이를 어떻게 관찰할 수 있나요? 스크립트는 트랜잭션이 중단된 후 IDBTransaction 인스턴스의 objectStore() 메서드를 사용하여 객체 저장소에 접근할 수는 없지만, IDBObjectStore 인스턴스에 대한 참조를 여전히 가지고 있을 수 있으며, 이 인스턴스의 name 및 indexNames 속성을 조회할 수 있습니다.
  6. transaction과 연결된 각 인덱스 핸들 handle에 대해, transaction 중 생성되거나 삭제된 인덱스의 핸들도 포함하여 다음을 수행합니다.

    1. handle의 인덱스가 transaction 중 새로 생성된 것이 아니면, handle의 이름을 해당 인덱스의 이름으로 설정합니다.

    참고: 이는 관련 IDBIndex 객체가 반환하는 name 값을 되돌립니다.

    이를 어떻게 관찰할 수 있나요? 스크립트는 트랜잭션이 중단된 후 IDBObjectStore 인스턴스의 index() 메서드를 사용하여 인덱스에 접근할 수는 없지만, IDBIndex 인스턴스에 대한 참조를 여전히 가지고 있을 수 있으며, 이 인스턴스의 name 속성을 조회할 수 있습니다.

참고: IDBDatabase 인스턴스의 name 속성은 중단된 업그레이드 트랜잭션이 새로운 데이터베이스를 생성 중이었더라도 수정되지 않습니다.

5.9. 성공 이벤트 발생

request에서 성공 이벤트를 발생시키려면 다음 단계를 실행합니다.

  1. event를 Event를 사용하여 이벤트를 생성한 결과로 둡니다.

  2. event의 type 속성을 "success"로 설정합니다.

  3. event의 bubbles 및 cancelable 속성을 false로 설정합니다.

  4. transaction을 request의 트랜잭션으로 둡니다.

  5. legacyOutputDidListenersThrowFlag를 처음에는 false로 둡니다.

  6. transaction의 상태가 비활성이면 transaction의 상태를 활성으로 설정합니다.

  7. legacyOutputDidListenersThrowFlag와 함께 request에서 event를 디스패치합니다.

  8. transaction의 상태가 활성이면 다음을 수행합니다.

    1. transaction의 상태를 비활성으로 설정합니다.

    2. legacyOutputDidListenersThrowFlag가 true이면 transaction 및 새로 생성된 "AbortError" DOMException과 함께 트랜잭션을 중단합니다.

    3. transaction의 요청 목록이 비어 있으면 transaction과 함께 트랜잭션을 커밋합니다.

5.10. 오류 이벤트 발생

request에서 오류 이벤트를 발생시키려면 다음 단계를 실행합니다.

  1. event를 Event를 사용하여 이벤트를 생성한 결과로 둡니다.

  2. event의 type 속성을 "error"로 설정합니다.

  3. event의 bubbles 및 cancelable 속성을 true로 설정합니다.

  4. transaction을 request의 트랜잭션으로 둡니다.

  5. legacyOutputDidListenersThrowFlag를 처음에는 false로 둡니다.

  6. transaction의 상태가 비활성이면 transaction의 상태를 활성으로 설정합니다.

  7. legacyOutputDidListenersThrowFlag와 함께 request에서 event를 디스패치합니다.

  8. transaction의 상태가 활성이면 다음을 수행합니다.

    1. transaction의 상태를 비활성으로 설정합니다.

    2. legacyOutputDidListenersThrowFlag가 true이면 transaction 및 새로 생성된 "AbortError" DOMException과 함께 트랜잭션을 중단하고 이 단계를 종료합니다. 이는 event의 취소됨 플래그가 false인 경우에도 수행됩니다.

      참고: 이는 오류 이벤트가 발생하고 이벤트 핸들러 중 하나가 예외를 던지면, transaction의 error 속성이 request의 오류가 아니라 AbortError로 설정된다는 뜻입니다. 이는 preventDefault()가 호출되지 않은 경우에도 마찬가지입니다.

    3. event의 취소됨 플래그가 false이면, transaction 및 request의 오류를 사용하여 트랜잭션을 중단하고 이 단계를 종료합니다.

    4. transaction의 요청 목록이 비어 있으면 transaction과 함께 트랜잭션을 커밋합니다.

5.11. 값 복제

transaction 동안 targetRealm에서 value의 복제본을 만들려면 다음 단계를 실행합니다.

  1. 단언: transaction의 상태는 활성입니다.

  2. transaction의 상태를 비활성으로 설정합니다.

    참고: 복제 작업으로 트리거되는 getter 또는 기타 부수 효과가 트랜잭션에 추가 요청을 하지 못하도록 트랜잭션을 비활성으로 만듭니다.

  3. serialized를 ? StructuredSerializeForStorage(value)로 둡니다.

  4. clone을 ? StructuredDeserialize(serialized, targetRealm)로 둡니다.

  5. transaction의 상태를 활성으로 설정합니다.

  6. clone을 반환합니다.

5.12. 여러 항목을 검색하기 위한 요청 생성

targetRealm, sourceHandle, kind, queryOrOptions 및 선택적 count를 사용하여 객체 저장소 또는 인덱스에서 여러 항목을 검색하기 위한 요청을 생성하려면 다음 단계를 실행합니다.

  1. source를 sourceHandle에서 얻은 인덱스 또는 객체 저장소로 둡니다. sourceHandle이 인덱스 핸들이면 source는 인덱스 핸들과 연결된 인덱스입니다. 그렇지 않으면 source는 객체 저장소 핸들과 연결된 객체 저장소입니다.

  2. source가 삭제되었다면 "InvalidStateError" DOMException을 던집니다.

  3. source가 인덱스이고 source의 객체 저장소가 삭제되었다면 "InvalidStateError" DOMException을 던집니다.

  4. transaction을 sourceHandle의 트랜잭션으로 둡니다.

  5. transaction의 상태가 활성이 아니면 "TransactionInactiveError" DOMException을 던집니다.

  6. range를 키 범위로 둡니다.

  7. direction을 커서 방향으로 둡니다.

  8. queryOrOptions를 사용하여 잠재적으로 유효한 키 범위인지 확인한 결과가 true이면 다음을 수행합니다.

    1. range를 queryOrOptions를 사용하여 값을 키 범위로 변환한 결과로 설정합니다. 모든 예외를 다시 던집니다.

    2. direction을 "next"로 설정합니다.

  9. 그렇지 않으면 다음을 수행합니다.

    1. range를 queryOrOptions["query"]를 사용하여 값을 키 범위로 변환한 결과로 설정합니다. 모든 예외를 다시 던집니다.

    2. count를 queryOrOptions["count"]로 설정합니다.

    3. direction을 queryOrOptions["direction"]으로 설정합니다.

  10. operation을 실행할 알고리즘으로 둡니다.

  11. source가 인덱스이면 operation을 targetRealm, source, range, kind, direction 및 주어진 경우 count와 함께 인덱스에서 여러 항목을 검색하는 것으로 설정합니다.

  12. 그렇지 않으면 operation을 targetRealm, source, range, kind, direction 및 주어진 경우 count와 함께 객체 저장소에서 여러 항목을 검색하는 것으로 설정합니다.

  13. sourceHandle 및 operation과 함께 요청을 비동기적으로 실행한 결과(IDBRequest)를 반환합니다.

참고: range는 검색할 레코드 항목을 식별하는 키 또는 키 범위(IDBKeyRange)일 수 있습니다. null이거나 주어지지 않으면 제한 없는 키 범위가 사용됩니다. count가 지정되고 범위 내 레코드가 count개보다 많으면 처음 count개만 검색됩니다.

6. 데이터베이스 작업

이 절에서는 데이터베이스의 객체 저장소 및 인덱스의 데이터에 수행되는 다양한 작업을 설명합니다. 이러한 작업은 요청을 비동기적으로 실행하는 단계에서 실행됩니다.

참고: 아래 작업 단계에서 StructuredDeserialize() 호출은 StructuredSerializeForStorage()의 이전 출력만 대상으로 하기 때문에 예외를 던지지 않는다고 단언할 수 있습니다(! 접두사로 표시됨).

6.1. 객체 저장소 저장 작업

store, value, 선택적 key 및 no-overwrite flag를 사용하여 객체 저장소에 레코드를 저장하려면 다음 단계를 실행합니다.

  1. store가 키 생성기를 사용하면 다음을 수행합니다.

    1. key가 undefined이면 다음을 수행합니다.

      1. key를 store에 대해 키를 생성한 결과로 둡니다.

      2. key가 failure이면 이 작업은 "ConstraintError" DOMException으로 실패합니다. 추가 단계를 수행하지 않고 이 알고리즘을 중단합니다.

      3. store가 또한 인라인 키를 사용하면 value, key 및 store의 키 경로를 사용하여 키 경로를 사용하여 값에 키를 삽입합니다.

    2. 그렇지 않으면 key를 사용하여 store의 키 생성기를 필요에 따라 갱신합니다.

  2. no-overwrite flag가 이 단계들에 주어졌고 true이며, store에 이미 레코드가 존재하고 그 키가 key와 같으면, 이 작업은 "ConstraintError" DOMException으로 실패합니다. 추가 단계를 수행하지 않고 이 알고리즘을 중단합니다.

  3. store에 이미 레코드가 존재하고 그 키가 key와 같으면, 객체 저장소에서 레코드를 삭제하는 단계를 사용하여 store에서 레코드를 제거합니다.

  4. key를 키로 하고 ! StructuredSerializeForStorage(value)를 값으로 하는 레코드를 store에 저장합니다. 레코드는 객체 저장소의 레코드 목록에 저장되며, 목록은 레코드의 키에 따라 오름차순으로 정렬됩니다.

  5. store를 참조하는 각 index에 대해:

    1. index key를 value, index의 키 경로 및 index의 multiEntry 플래그를 사용하여 키 경로를 사용해 값에서 키를 추출한 결과로 둡니다.

    2. index key가 예외이거나, 유효하지 않거나, failure이면 index에 대해 더 이상 아무 작업도 하지 않고 다음 인덱스에 대해 이 단계를 계속합니다.

      참고: 이 단계에서 던져진 예외는 다시 던지지 않습니다.

    3. index의 multiEntry 플래그가 false이거나 index key가 배열 키가 아니고, index에 이미 레코드가 있고 그 키가 index key와 같으며, index의 고유 플래그가 true이면 이 작업은 "ConstraintError" DOMException으로 실패합니다. 추가 단계를 수행하지 않고 이 알고리즘을 중단합니다.

    4. index의 multiEntry 플래그가 true이고 index key가 배열 키이며, index에 이미 레코드가 있고 그 키가 index key의 하위 키 중 하나와 같으며, index의 고유 플래그가 true이면 이 작업은 "ConstraintError" DOMException으로 실패합니다. 추가 단계를 수행하지 않고 이 알고리즘을 중단합니다.

    5. index의 multiEntry 플래그가 false이거나 index key가 배열 키가 아니면 index key를 키로 하고 key를 값으로 하는 레코드를 index에 저장합니다. 레코드는 index의 레코드 목록에 저장되며, 목록은 우선 레코드의 키를 기준으로, 다음으로 레코드의 값을 기준으로 오름차순으로 정렬됩니다.

    6. index의 multiEntry 플래그가 true이고 index key가 배열 키이면 index key의 하위 키의 각 subkey에 대해 subkey를 키로 하고 key를 값으로 하는 레코드를 index에 저장합니다. 레코드들은 index의 레코드 목록에 저장되며, 목록은 우선 레코드의 키를 기준으로, 다음으로 레코드의 값을 기준으로 오름차순으로 정렬됩니다.

      참고: 하위 키가 없는 것도 유효합니다. 이 경우 인덱스에 레코드가 추가되지 않습니다.

      참고: 하위 키의 어떤 멤버 자체가 배열 키이더라도, 그 멤버는 인덱스 레코드의 키로 직접 사용됩니다. 중첩된 배열 키는 여러 행을 생성하도록 평탄화되거나 "풀리지" 않으며, 가장 바깥쪽 배열 키만 그렇게 처리됩니다.

  6. key를 반환합니다.

6.2. 객체 저장소 검색 작업

targetRealm, store 및 range를 사용하여 객체 저장소에서 값을 검색하려면 다음 단계를 실행합니다. 이 단계들은 undefined, ECMAScript 값 또는 오류(DOMException)를 반환합니다.

  1. record를 store의 레코드 목록에서 키가 range 안에 있는 첫 번째 레코드로 둡니다(있는 경우).

  2. record를 찾지 못했다면 undefined를 반환합니다.

  3. serialized를 record의 값으로 둡니다. 기본 스토리지에서 값을 읽는 중 오류가 발생하면 새로 생성된 "NotReadableError" DOMException을 반환합니다.

  4. ! StructuredDeserialize(serialized, targetRealm)을 반환합니다.

store 및 range를 사용하여 객체 저장소에서 키를 검색하려면 다음 단계를 실행합니다.

  1. record를 store의 레코드 목록에서 키가 range 안에 있는 첫 번째 레코드로 둡니다(있는 경우).

  2. record를 찾지 못했다면 undefined를 반환합니다.

  3. record의 키를 사용하여 키를 값으로 변환한 결과를 반환합니다.

targetRealm, store, range, kind, direction 및 선택적 count를 사용하여 객체 저장소에서 여러 항목을 검색하려면 다음 단계를 실행합니다.

  1. count가 주어지지 않았거나 0(영)이면 count를 infinity로 둡니다.

  2. records를 빈 목록(레코드의 목록)으로 둡니다.

  3. direction이 "next" 또는 "nextunique"이면, records를 store의 레코드 목록 중 키가 range 안에 있는 처음 count개로 설정합니다.

  4. direction이 "prev" 또는 "prevunique"이면, records를 store의 레코드 목록 중 키가 range 안에 있는 마지막 count개로 설정합니다.

  5. list를 빈 목록으로 둡니다.

  6. records의 각 record에 대해 kind에 따라 다음을 수행합니다.

    "key"
    1. key를 record의 키를 사용하여 키를 값으로 변환한 결과로 둡니다.

    2. key를 list에 추가합니다.

    "value"
    1. serialized를 record의 값으로 둡니다.

    2. value를 ! StructuredDeserialize(serialized, targetRealm)로 둡니다.

    3. value를 list에 추가합니다.

    "record"
    1. key를 record의 키로 둡니다.

    2. serialized를 record의 값으로 둡니다.

    3. value를 ! StructuredDeserialize(serialized, targetRealm)로 둡니다.

    4. recordSnapshot을 새로운 레코드 스냅샷으로 두고, 그 키를 key로, 값을 value로, 그리고 기본 키를 key로 설정합니다.

    5. recordSnapshot을 list에 추가합니다.

  7. list를 반환합니다.

6.3. 인덱스 검색 작업

targetRealm, index 및 range를 사용하여 인덱스에서 참조된 값을 검색하려면 다음 단계를 실행합니다.

  1. record를 index의 레코드 목록에서 키가 range 안에 있는 첫 번째 레코드로 둡니다(있는 경우).

  2. record를 찾지 못했다면 undefined를 반환합니다.

  3. serialized를 record의 참조된 값으로 둡니다.

  4. ! StructuredDeserialize(serialized, targetRealm)을 반환합니다.

index 및 range를 사용하여 인덱스에서 값을 검색하려면 다음 단계를 실행합니다.

  1. record를 index의 레코드 목록에서 키가 range 안에 있는 첫 번째 레코드로 둡니다(있는 경우).

  2. record를 찾지 못했다면 undefined를 반환합니다.

  3. record의 값을 사용하여 키를 값으로 변환한 결과를 반환합니다.

targetRealm, index, range, kind, direction 및 선택적 count를 사용하여 인덱스에서 여러 항목을 검색하려면 다음 단계를 실행합니다.

  1. count가 주어지지 않았거나 0(영)이면 count를 infinity로 둡니다.

  2. records를 빈 목록(레코드의 목록)으로 둡니다.

  3. direction에 따라 다음을 수행합니다.

    "next"
    1. records를 index의 레코드 목록 중 키가 range 안에 있는 처음 count개로 설정합니다.

    "nextunique"
    1. rangeRecords를 index의 레코드 목록 중 키가 range 안에 있는 항목을 포함하는 목록으로 둡니다.

    2. rangeRecordsLength를 rangeRecords의 크기로 둡니다.

    3. i를 0으로 둡니다.

    4. i가 rangeRecordsLength보다 작은 동안 다음을 수행합니다.

      1. i를 1 증가시킵니다.

      2. record의 크기가 count와 같으면 중단합니다.

      3. |rangeRecords[i]| 및 |rangeRecords[i-1]|의 키를 사용하여 두 키를 비교한 결과가 같으면 계속합니다.

      4. 그렇지 않으면 |rangeRecords[i]|를 records에 추가합니다.

    "prev"
    1. records를 index의 레코드 목록 중 키가 range 안에 있는 마지막 count개로 설정합니다.

    "prevunique"
    1. rangeRecords를 index의 레코드 목록 중 키가 range 안에 있는 항목을 포함하는 목록으로 둡니다.

    2. rangeRecordsLength를 rangeRecords의 크기로 둡니다.

    3. i를 0으로 둡니다.

    4. i가 rangeRecordsLength보다 작은 동안 다음을 수행합니다.

      1. i를 1 증가시킵니다.

      2. record의 크기가 count와 같으면 중단합니다.

      3. |rangeRecords[i]| 및 |rangeRecords[i-1]|의 키를 사용하여 두 키를 비교한 결과가 같으면 계속합니다.

      4. 그렇지 않으면 |rangeRecords[i]|를 records 앞에 추가합니다.

  4. list를 빈 목록으로 둡니다.

  5. records의 각 record에 대해 kind에 따라 다음을 수행합니다.

    "key"
    1. key를 record의 값을 사용하여 키를 값으로 변환한 결과로 둡니다.

    2. key를 list에 추가합니다.

    "value"
    1. serialized를 record의 참조된 값으로 둡니다.

    2. value를 ! StructuredDeserialize(serialized, targetRealm)로 둡니다.

    3. value를 list에 추가합니다.

    "record"
    1. index key를 record의 키로 둡니다.

    2. key를 record의 값으로 둡니다.

    3. serialized를 record의 참조된 값으로 둡니다.

    4. value를 ! StructuredDeserialize(serialized, targetRealm)로 둡니다.

    5. recordSnapshot을 새로운 레코드 스냅샷으로 두고, 그 키를 index key로, 값을 value로, 그리고 기본 키를 key로 설정합니다.

    6. recordSnapshot을 list에 추가합니다.

  6. list를 반환합니다.

6.4. 객체 저장소 삭제 작업

store 및 range를 사용하여 객체 저장소에서 레코드를 삭제하려면 다음 단계를 실행합니다.

  1. store의 레코드 목록에서 키가 range 안에 있는 모든 레코드를 제거합니다(있는 경우).

  2. store를 참조하는 각 index에 대해, 값이 range 안에 있는 모든 레코드를 index의 레코드 목록에서 제거합니다(그러한 레코드가 있는 경우).

  3. undefined를 반환합니다.

6.5. 레코드 개수 계산 작업

source 및 range를 사용하여 범위의 레코드 수를 계산하려면 다음 단계를 실행합니다.

  1. count를 source의 레코드 목록에서 키가 range 안에 있는 레코드의 수로 둡니다(있는 경우).

  2. count를 반환합니다.

6.6. 객체 저장소 비우기 작업

store로 객체 저장소를 비우려면 다음 단계를 실행합니다.

  1. store에서 모든 레코드를 제거합니다.

  2. store를 참조하는 모든 인덱스에서 모든 레코드를 제거합니다.

  3. undefined를 반환합니다.

6.7. 커서 반복 작업

targetRealm, cursor, 반복할 선택적 key 및 primaryKey, 그리고 선택적 count를 사용하여 커서를 반복하려면 다음 단계를 실행합니다.

  1. source를 cursor의 소스로 둡니다.

  2. direction을 cursor의 방향으로 둡니다.

  3. 단언: primaryKey가 주어졌다면 source는 인덱스이고 direction은 "next" 또는 "prev"입니다.

  4. records를 source에 있는 레코드 목록으로 둡니다.

    참고: records는 항상 키의 오름차순으로 정렬됩니다. source가 인덱스인 경우 records는 두 번째로 값의 오름차순으로 정렬됩니다 (인덱스의 값은 참조되는 객체 저장소에 있는 레코드의 키입니다).

  5. range를 cursor의 범위로 둡니다.

  6. position을 cursor의 위치로 둡니다.

  7. object store position을 cursor의 객체 저장소 위치로 둡니다.

  8. count가 주어지지 않았으면 count를 1로 둡니다.

  9. count가 0보다 큰 동안 다음을 수행합니다.

    1. direction에 따라 다음을 수행합니다.

      "next"

      found record를 records에서 다음 요구 사항을 모두 만족하는 첫 번째 레코드로 둡니다.

      • key가 정의되어 있으면:

      • primaryKey가 정의되어 있으면:

      • position이 정의되어 있고 source가 객체 저장소이면:

        • 레코드의 키가 position보다 큽니다.

      • position이 정의되어 있고 source가 인덱스이면:

        • 레코드의 키가 position과 같고, 레코드의 값이 object store position보다 큽니다.

        • 레코드의 키가 position보다 큽니다.

      • 레코드의 키가 range 안에 있습니다.

      "nextunique"

      found record를 records에서 다음 요구 사항을 모두 만족하는 첫 번째 레코드로 둡니다.

      • key가 정의되어 있으면:

      • position이 정의되어 있으면:

        • 레코드의 키가 position보다 큽니다.

      • 레코드의 키가 range 안에 있습니다.

      "prev"

      found record를 records에서 다음 요구 사항을 모두 만족하는 마지막 레코드로 둡니다.

      "prevunique"

      temp record를 records에서 다음 요구 사항을 모두 만족하는 마지막 레코드로 둡니다.

      • key가 정의되어 있으면:

      • position이 정의되어 있으면:

      • 레코드의 키가 range 안에 있습니다.

      temp record가 정의되어 있으면 found record를 records에서 키가 temp record의 키와 같은 첫 번째 레코드로 둡니다.

      참고: "prevunique"로 반복하면 "nextunique"가 방문하는 것과 동일한 레코드를 역순으로 방문합니다.

    2. found record가 정의되지 않았으면 다음을 수행합니다.

      1. cursor의 키를 undefined로 설정합니다.

      2. source가 인덱스이면 cursor의 객체 저장소 위치를 undefined로 설정합니다.

      3. cursor의 키 전용 플래그가 false이면 cursor의 값을 undefined로 설정합니다.

      4. null을 반환합니다.

    3. position을 found record의 키로 둡니다.

    4. source가 인덱스이면 object store position을 found record의 값으로 둡니다.

    5. count를 1 감소시킵니다.

  10. cursor의 위치를 position으로 설정합니다.

  11. source가 인덱스이면 cursor의 객체 저장소 위치를 object store position으로 설정합니다.

  12. cursor의 키를 found record의 키로 설정합니다.

  13. cursor의 키 전용 플래그가 false이면 다음을 수행합니다.

    1. serialized를 source가 객체 저장소이면 found record의 값으로 두고, 그렇지 않으면 found record의 참조된 값으로 둡니다.

    2. cursor의 값을 ! StructuredDeserialize(serialized, targetRealm)로 설정합니다.

  14. cursor의 값 획득 플래그를 true로 설정합니다.

  15. cursor를 반환합니다.

7. ECMAScript 바인딩

이 절에서는 이 명세에 정의된 키 값이 ECMAScript 값으로 또는 ECMAScript 값에서 어떻게 변환되는지, 그리고 키 경로를 사용하여 ECMAScript 값에서 키를 어떻게 추출하고 삽입할 수 있는지 정의합니다. 이 절은 ECMAScript 언어 명세의 유형과 알고리즘을 참조하며 일부 알고리즘 규약을 사용합니다. [ECMA-262] 여기에서 자세히 설명하지 않은 변환은 [WEBIDL]에 정의되어 있습니다.

7.1. 값에서 키 추출

value, keyPath 및 선택적 multiEntry flag를 사용하여 키 경로를 사용하여 값에서 키를 추출하려면 다음 단계를 실행합니다. 이 단계의 결과는 키, invalid 또는 failure이며, 단계에서 예외를 던질 수도 있습니다.

  1. r을 value 및 keyPath를 사용하여 값에서 키 경로를 평가한 결과로 둡니다. 모든 예외를 다시 던집니다.

  2. r이 failure이면 failure를 반환합니다.

  3. key를 multiEntry flag가 false이면 r을 사용하여 값을 키로 변환한 결과로 두고, 그렇지 않으면 r을 사용하여 값을 multiEntry 키로 변환한 결과로 둡니다. 모든 예외를 다시 던집니다.

  4. key가 "invalid value" 또는 "invalid type"이면 invalid를 반환합니다.

  5. key를 반환합니다.

value 및 keyPath를 사용하여 값에서 키 경로를 평가하려면 다음 단계를 실행합니다. 이 단계의 결과는 ECMAScript 값 또는 failure이며, 단계에서 예외를 던질 수도 있습니다.

  1. keyPath가 문자열의 목록이면 다음을 수행합니다.

    1. result를 표현식 []로 생성한 것처럼 생성된 새로운 Array 객체로 둡니다.

    2. i를 0으로 둡니다.

    3. keyPath의 각 item에 대해 다음을 수행합니다.

      1. key를 item 및 value를 사용하여 재귀적으로 값에서 키 경로를 평가한 결과로 둡니다.

      2. 단언: key는 갑작스러운 완료가 아닙니다.

      3. key가 failure이면 전체 알고리즘을 중단하고 failure를 반환합니다.

      4. p를 ! ToString(i)로 둡니다.

      5. status를 CreateDataProperty(result, p, key)로 둡니다.

      6. 단언: status는 true입니다.

      7. i를 1 증가시킵니다.

    4. result를 반환합니다.

      참고: 키 경로 시퀀스는 중첩될 수 없으므로 이는 항상 한 단계만 "재귀"합니다.

  2. keyPath가 빈 문자열이면 value를 반환하고 나머지 단계를 건너뜁니다.

  3. identifiers를 U+002E FULL STOP 문자(.)에서 keyPath를 엄격하게 분할한 결과로 둡니다.

  4. identifiers의 각 identifier에 대해 적절한 아래 단계로 이동합니다.

    Type(value)가 String이고 identifier가 "length"인 경우

    value를 value의 요소 수와 같은 Number로 둡니다.

    value가 Array이고 identifier가 "length"인 경우

    value를 ! ToLength(! Get(value, "length"))로 둡니다.

    value가 Blob이고 identifier가 "size"인 경우

    value를 value의 size와 같은 Number로 둡니다.

    value가 Blob이고 identifier가 "type"인 경우

    value를 value의 type과 같은 String으로 둡니다.

    value가 File이고 identifier가 "name"인 경우

    value를 value의 name과 같은 String으로 둡니다.

    value가 File이고 identifier가 "lastModified"인 경우

    value를 value의 lastModified와 같은 Number로 둡니다.

    그 밖의 경우
    1. Type(value)가 Object가 아니면 failure를 반환합니다.

    2. hop을 ! HasOwnProperty(value, identifier)로 둡니다.

    3. hop이 false이면 failure를 반환합니다.

    4. value를 ! Get(value, identifier)로 둡니다.

    5. value가 undefined이면 failure를 반환합니다.

  5. 단언: value는 갑작스러운 완료가 아닙니다.

  6. value를 반환합니다.

참고: 이 알고리즘은 StructuredDeserialize의 출력인 값에만 적용되고 "자체" 속성에만 접근하므로 위 단계에서 단언할 수 있습니다.

7.2. 값에 키 삽입

참고: 이 절에서 사용되는 키 경로는 항상 문자열이며 시퀀스가 아닙니다. 키 생성기를 가지면서 동시에 시퀀스인 키 경로를 가진 객체 저장소를 생성할 수 없기 때문입니다.

value 및 keyPath를 사용하여 값에 키를 삽입할 수 있는지 확인하려면 다음 단계를 실행합니다. 이 단계의 결과는 true 또는 false입니다.

  1. identifiers를 U+002E FULL STOP 문자(.)에서 keyPath를 엄격하게 분할한 결과로 둡니다.

  2. 단언: identifiers는 비어 있지 않습니다.

  3. identifiers의 마지막 항목을 제거합니다.

  4. identifiers에 남아 있는 각 identifier에 대해, 있는 경우 다음을 수행합니다.

    1. value가 Object 또는 Array가 아니면 false를 반환합니다.

    2. hop을 ! HasOwnProperty(value, identifier)로 둡니다.

    3. hop이 false이면 true를 반환합니다.

    4. value를 ! Get(value, identifier)로 둡니다.

  5. value가 Object 또는 Array이면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

참고: 이 알고리즘은 StructuredDeserialize의 출력인 값에만 적용되므로 위 단계에서 단언할 수 있습니다.

value, key 및 keyPath를 사용하여 키 경로를 사용하여 값에 키를 삽입하려면 다음 단계를 실행합니다.

  1. identifiers를 U+002E FULL STOP 문자(.)에서 keyPath를 엄격하게 분할한 결과로 둡니다.

  2. 단언: identifiers는 비어 있지 않습니다.

  3. last를 identifiers의 마지막 항목으로 두고 목록에서 제거합니다.

  4. identifiers에 남아 있는 각 identifier에 대해 다음을 수행합니다.

    1. 단언: value는 Object 또는 Array입니다.

    2. hop을 ! HasOwnProperty(value, identifier)로 둡니다.

    3. hop이 false이면 다음을 수행합니다.

      1. o를 표현식 ({})로 생성한 것처럼 생성된 새로운 Object로 둡니다.

      2. status를 CreateDataProperty(value, identifier, o)로 둡니다.

      3. 단언: status는 true입니다.

    4. value를 ! Get(value, identifier)로 둡니다.

  5. 단언: value는 Object 또는 Array입니다.

  6. keyValue를 key를 사용하여 키를 값으로 변환한 결과로 둡니다.

  7. status를 CreateDataProperty(value, last, keyValue)로 둡니다.

  8. 단언: status는 true입니다.

참고: 이 알고리즘은 StructuredDeserialize의 출력인 값에만 적용되고, 값에 키를 삽입할 수 있는지 확인하는 단계가 실행되었으므로 위 단계에서 단언할 수 있습니다.

7.3. 키를 값으로 변환

key를 사용하여 키를 값으로 변환하려면 다음 단계를 실행합니다. 이 단계들은 ECMAScript 값을 반환합니다.

  1. type을 key의 유형으로 둡니다.

  2. value를 key의 값으로 둡니다.

  3. type에 따라 다음을 수행합니다.

    number

    value와 같은 ECMAScript Number 값을 반환합니다.

    string

    value와 같은 ECMAScript String 값을 반환합니다.

    date
    1. date를 단일 인수 value로 ECMAScript Date 생성자를 실행한 결과로 둡니다.

    2. 단언: date는 갑작스러운 완료가 아닙니다.

    3. date를 반환합니다.

    binary
    1. len을 value의 길이로 둡니다.

    2. buffer를 len을 사용하여 ECMAScript ArrayBuffer 생성자를 실행한 결과로 둡니다.

    3. 단언: buffer는 갑작스러운 완료가 아닙니다.

    4. buffer의 [[ArrayBufferData]] 내부 슬롯의 항목을 value의 항목으로 설정합니다.

    5. buffer를 반환합니다.

    array
    1. array를 인수 없이 ECMAScript Array 생성자를 실행한 결과로 둡니다.

    2. 단언: array는 갑작스러운 완료가 아닙니다.

    3. len을 value의 크기로 둡니다.

    4. index를 0으로 둡니다.

    5. index가 len보다 작은 동안 다음을 수행합니다.

      1. entry를 value[index]를 사용하여 키를 값으로 변환한 결과로 둡니다.

      2. status를 CreateDataProperty(array, index, entry)로 둡니다.

      3. 단언: status는 true입니다.

      4. index를 1 증가시킵니다.

    6. array를 반환합니다.

7.4. 값을 키로 변환

ECMAScript 값 input 및 선택적 집합 seen을 사용하여 값을 키로 변환하려면 다음 단계를 실행합니다. 이 단계의 결과는 키, "invalid value", "invalid type"이며, 단계에서 예외를 던질 수도 있습니다.

  1. seen이 주어지지 않았으면 seen을 새로운 빈 집합으로 둡니다.

  2. seen이 input을 포함하면 "invalid value"를 반환합니다.

  3. 아래의 적절한 단계로 이동합니다.

    Type(input)이 Number인 경우
    1. input이 NaN이면 "invalid value"를 반환합니다.

    2. 그렇지 않으면 키를 새로 반환하며, 유형은 number이고 값은 input입니다.

    input이 Date인 경우 ([[DateValue]] 내부 슬롯을 가짐)
    1. ms를 input의 [[DateValue]] 내부 슬롯 값으로 둡니다.

    2. ms가 NaN이면 "invalid value"를 반환합니다.

    3. 그렇지 않으면 키를 새로 반환하며 유형은 date이고 값은 ms입니다.

    Type(input)이 String인 경우
    1. 키를 새로 반환하며, 유형은 string이고 값은 input입니다.

    input이 버퍼 소스 유형인 경우
    1. input이 분리되어 있으면 "invalid value"를 반환합니다.

    2. bytes를 input에서 버퍼 소스가 보유한 바이트의 복사본을 가져온 결과로 둡니다.

    3. 키를 새로 반환하며, 유형은 binary이고 값은 bytes입니다.

    input이 Array exotic object인 경우
    1. len을 ? ToLength( ? Get(input, "length"))로 둡니다.

    2. input을 seen에 추가합니다.

    3. keys를 새로운 빈 목록으로 둡니다.

    4. index를 0으로 둡니다.

    5. index가 len보다 작은 동안 다음을 수행합니다.

      1. hop을 ? HasOwnProperty(input, index)로 둡니다.

      2. hop이 false이면 "invalid value"를 반환합니다.

      3. entry를 ? Get(input, index)로 둡니다.

      4. key를 entry 및 seen을 인수로 사용하여 값을 키로 변환한 결과로 둡니다.

      5. ReturnIfAbrupt(key).

      6. key가 "invalid value" 또는 "invalid type"이면 이 단계를 중단하고 "invalid value"를 반환합니다.

      7. key를 keys에 추가합니다.

      8. index를 1 증가시킵니다.

    6. 배열 키를 새로 반환하며, 값은 keys입니다.

    그 밖의 경우

    "invalid type"을 반환합니다.

ECMAScript 값 input을 사용하여 값을 multiEntry 키로 변환하려면 다음 단계를 실행합니다. 이 단계의 결과는 키, "invalid value", "invalid type"이며, 단계에서 예외를 던질 수도 있습니다.

  1. input이 Array exotic object이면 다음을 수행합니다.

    1. len을 ? ToLength( ? Get(input, "length"))로 둡니다.

    2. seen을 input만 포함하는 새로운 집합으로 둡니다.

    3. keys를 새로운 빈 목록으로 둡니다.

    4. index를 0으로 둡니다.

    5. index가 len보다 작은 동안 다음을 수행합니다.

      1. entry를 Get(input, index)로 둡니다.

      2. entry가 갑작스러운 완료가 아니면 다음을 수행합니다.

        1. key를 entry 및 seen을 인수로 사용하여 값을 키로 변환한 결과로 둡니다.

        2. key가 "invalid value", "invalid type" 또는 갑작스러운 완료가 아니고, keys에 key와 같은 항목이 없다면, key를 keys에 추가합니다.

      3. index를 1 증가시킵니다.

    6. 배열 키를 새로 반환하며 값은 keys로 설정됩니다.

  2. 그렇지 않으면 input을 인수로 사용하여 값을 키로 변환한 결과를 반환합니다. 모든 예외를 다시 던집니다.

참고: 이 단계들은 값을 키로 변환하는 단계와 비슷하지만, 최상위 값이 Array이면 키로 변환할 수 없는 멤버는 무시되고 중복 항목은 제거됩니다.

예를 들어 값 [10, 20, null, 30, 20]은 하위 키가 10, 20, 30인 배열 키로 변환됩니다.

8. 개인정보 보호 고려 사항

이 절은 규범적이지 않습니다.

8.1. 사용자 추적

서드파티 호스트(또는 여러 사이트에 배포되는 콘텐츠를 얻을 수 있는 모든 객체)는 클라이언트 측 데이터베이스에 저장된 고유 식별자를 사용하여 여러 세션에 걸쳐 사용자를 추적하고 사용자의 활동 프로필을 구축할 수 있습니다. 사용자의 실제 신원 객체를 알고 있는 사이트(예: 인증된 자격 증명을 요구하는 전자상거래 사이트)와 함께 사용될 경우, 이는 순수하게 익명으로 웹을 사용하는 환경보다 억압적인 집단이 개인을 더욱 정확하게 표적으로 삼을 수 있게 할 수 있습니다.

사용자 추적 위험을 완화하기 위해 사용할 수 있는 여러 기법이 있습니다.

서드파티 스토리지 차단

사용자 에이전트는 데이터베이스 객체에 대한 접근을 브라우징 컨텍스트의 최상위 문서 도메인에서 유래한 스크립트로 제한할 수 있습니다. 예를 들어 다른 도메인의 페이지가 iframe에서 실행되는 경우 API 접근을 거부할 수 있습니다.

저장된 데이터 만료

사용자 에이전트는 일정 시간이 지난 후 저장된 데이터를 자동으로 삭제할 수 있습니다.

그러면 사이트가 사이트 자체에서 사용자를 인증할 때(예: 구매하거나 서비스에 로그인하는 경우)에만 여러 세션에 걸쳐 사용자를 추적할 수 있으므로 사이트의 사용자 추적 능력을 제한할 수 있습니다.

하지만 이는 사용자의 데이터도 위험에 빠뜨립니다.

영구 스토리지를 쿠키처럼 취급

사용자 에이전트는 데이터베이스 기능을 HTTP 세션 쿠키와 강하게 연관되도록 사용자에게 표시해야 합니다. [COOKIES]

이는 사용자가 이러한 스토리지를 적절한 경계심을 가지고 바라보도록 유도할 수 있습니다.

데이터베이스 접근에 대한 사이트별 허용 목록

사용자 에이전트는 사이트가 이 기능을 사용하기 전에 사용자가 데이터베이스 접근을 승인하도록 요구할 수 있습니다.

서드파티 스토리지의 출처 표시

사용자 에이전트는 데이터가 저장되도록 한 서드파티 출처의 콘텐츠를 포함한 사이트의 출처를 기록할 수 있습니다.

이 정보가 현재 영구 스토리지에 있는 데이터를 보여 주는 데 사용된다면, 사용자가 영구 스토리지의 어떤 부분을 정리할지 정보에 근거해 결정할 수 있습니다. 차단 목록("이 데이터를 삭제하고 이 도메인이 다시는 데이터를 저장하지 못하게 함")과 결합하면 사용자는 신뢰하는 사이트로 영구 스토리지 사용을 제한할 수 있습니다.

공유 차단 목록

사용자 에이전트는 사용자가 영구 스토리지 도메인 차단 목록을 공유할 수 있게 할 수 있습니다.

이를 통해 커뮤니티가 함께 행동하여 개인정보를 보호할 수 있습니다.

이러한 제안은 사용자 추적을 위해 이 API를 단순하게 사용하는 것을 막지만 완전히 차단하지는 않습니다. 하나의 도메인 내에서 사이트는 세션 동안 계속 사용자를 추적할 수 있으며, 사이트가 얻은 식별 정보(이름, 신용카드 번호, 주소)와 함께 이 모든 정보를 서드파티에 전달할 수 있습니다. 서드파티가 여러 사이트와 협력하여 이러한 정보를 얻으면 여전히 프로필을 만들 수 있습니다.

그러나 사용자 에이전트의 협력이 전혀 없어도 사용자 추적은 어느 정도 가능합니다. 예를 들어 URL의 세션 식별자를 사용할 수 있는데, 이는 이미 무해한 목적으로 흔히 사용되지만 사용자 추적 용도로 쉽게 전용될 수 있는 기법입니다(심지어 소급해서도). 그런 다음 방문자의 IP 주소 및 기타 사용자별 데이터(예: 사용자 에이전트 헤더와 구성 설정)를 사용하여 별도의 세션을 일관된 사용자 프로필로 결합하고, 이 정보를 다른 사이트와 공유할 수 있습니다.

영구 스토리지의 사용자 인터페이스가 이 명세에 설명된 영구 스토리지 기능의 데이터를 HTTP 세션 쿠키의 데이터와 별도로 표시하면, 사용자는 한쪽의 데이터만 삭제하고 다른 쪽은 삭제하지 않을 가능성이 큽니다. 그러면 사이트가 두 기능을 서로의 중복 백업으로 사용하여 사용자의 개인정보 보호 시도를 무력화할 수 있습니다.

8.3. 데이터의 민감성

사용자 에이전트는 영구적으로 저장된 데이터를 잠재적으로 민감한 것으로 취급해야 합니다. 이메일, 일정 약속, 건강 기록 또는 기타 기밀 문서가 이 메커니즘에 저장될 가능성이 충분히 있습니다.

이를 위해 사용자 에이전트는 데이터를 삭제할 때 기본 스토리지에서도 즉시 삭제되도록 해야 합니다.

9. 보안 고려 사항

9.1. DNS 스푸핑 공격

DNS 스푸핑 공격 가능성 때문에 특정 도메인에 속한다고 주장하는 호스트가 실제로 그 도메인에 속한다고 보장할 수 없습니다. 이를 완화하기 위해 페이지는 TLS를 사용할 수 있습니다. TLS를 사용하는 페이지는 같은 도메인에서 왔음을 식별하는 인증서를 가진 TLS 사용 페이지만 자신의 데이터베이스에 접근할 수 있음을 확신할 수 있습니다.

9.2. 디렉터리 간 공격

하나의 호스트 이름을 공유하는 서로 다른 작성자, 예를 들어 geocities.com에 콘텐츠를 호스팅하는 사용자들은 모두 하나의 데이터베이스 집합을 공유합니다.

경로명으로 접근을 제한하는 기능은 없습니다. 따라서 공유 호스트의 작성자는 다른 작성자가 데이터를 읽고 덮어쓰는 것이 매우 쉽기 때문에 이러한 기능을 사용하지 않는 것이 권장됩니다.

참고: 경로 제한 기능이 제공되더라도 일반적인 DOM 스크립팅 보안 모델 때문에 이러한 보호를 우회하고 어떤 경로에서든 데이터에 접근하는 것은 매우 쉽습니다.

9.3. 구현 위험

이러한 영구 스토리지 기능을 구현할 때의 두 가지 주요 위험은 악의적인 사이트가 다른 도메인의 정보를 읽도록 허용하는 것과, 악의적인 사이트가 다른 도메인에서 나중에 읽히는 정보를 쓰도록 허용하는 것입니다.

서드파티 사이트가 자신의 도메인에서 읽어서는 안 되는 데이터를 읽도록 허용하면 정보 유출이 발생합니다. 예를 들어 한 도메인의 사용자 쇼핑 희망 목록을 다른 도메인이 타기팅 광고에 사용할 수 있거나, 워드 프로세싱 사이트가 저장한 사용자의 작업 중 기밀 문서를 경쟁 회사의 사이트가 살펴볼 수 있습니다.

서드파티 사이트가 다른 도메인의 영구 스토리지에 데이터를 쓰도록 허용하면 마찬가지로 위험한 정보 스푸핑이 발생할 수 있습니다. 예를 들어 악의적인 사이트가 사용자의 희망 목록에 레코드를 추가하거나, 사용자의 세션 식별자를 악의적인 사이트가 피해 사이트에서 사용자의 행동을 추적하는 데 사용할 수 있는 알려진 ID로 설정할 수 있습니다.

따라서 이 명세에 설명된 스토리지 키 파티셔닝 모델을 엄격하게 따르는 것은 사용자 보안에 중요합니다.

호스트 이름이나 데이터베이스 이름을 사용하여 파일 시스템에 영구 저장하기 위한 경로를 구성하는 경우, 상대 경로(예: "../")를 사용하여 공격자가 다른 스토리지 키의 정보에 접근하지 못하도록 적절히 이스케이프해야 합니다.

9.4. 영구 저장 위험

실제 구현은 데이터를 비휘발성 저장 매체에 영구 저장합니다. 데이터는 저장할 때 직렬화되고 검색할 때 역직렬화되지만, 직렬화 형식의 세부 사항은 사용자 에이전트마다 다릅니다. 사용자 에이전트는 시간이 지나면서 직렬화 형식을 변경할 가능성이 큽니다. 예를 들어 새로운 데이터 유형을 처리하거나 성능을 개선하도록 형식이 갱신될 수 있습니다. 따라서 이 명세의 동작 요구 사항을 충족하기 위해 구현은 이전 직렬화 형식을 어떤 방식으로든 처리해야 합니다. 이전 데이터를 부적절하게 처리하면 보안 문제가 발생할 수 있습니다. 기본적인 직렬화 문제 외에도 직렬화된 데이터는 최신 버전의 사용자 에이전트에서 유효하지 않은 가정을 인코딩할 수 있습니다.

실제 예는 RegExp 유형입니다. StructuredSerializeForStorage 작업은 RegExp 객체의 직렬화를 허용합니다. 일반적인 사용자 에이전트는 입력 데이터가 전달되고 결과가 반환되는 방식에 대한 가정을 바탕으로 정규 표현식을 네이티브 머신 명령어로 컴파일합니다. 이 내부 상태가 데이터베이스에 저장되는 데이터의 일부로 직렬화되면 나중에 내부 표현을 역직렬화할 때 다양한 문제가 발생할 수 있습니다. 예를 들어 코드에 데이터가 전달되는 방식이 변경되었을 수 있습니다. 컴파일러 출력의 보안 버그가 사용자 에이전트 업데이트에서 식별되고 수정되었더라도 직렬화된 내부 상태에는 그대로 남아 있을 수 있습니다.

사용자 에이전트는 이전 데이터를 식별하고 적절하게 처리해야 합니다. 한 가지 방법은 직렬화 형식에 버전 식별자를 포함하고, 이전 데이터가 발견되면 스크립트에서 볼 수 있는 상태로부터 내부 상태를 재구성하는 것입니다.

10. 접근성 고려 사항

이 절은 규범적이지 않습니다.

이 명세에 설명된 API에는 제한적인 접근성 고려 사항이 있습니다.

API는 구조화된 콘텐츠를 저장할 수 있습니다. 텍스트 콘텐츠는 문자열로 저장할 수 있습니다. 개발자가 이미지나 오디오와 같은 대체 비텍스트 콘텐츠를 Blob, File, 또는 ImageData 객체로 저장할 수 있도록 API가 지원합니다. API를 사용하여 동적 콘텐츠 애플리케이션을 만드는 개발자는 다양한 기술과 요구 사항을 가진 사용자가 콘텐츠에 접근할 수 있도록 해야 합니다.

API 자체는 이를 위한 특정 메커니즘을 정의하지 않지만, 구조화된 콘텐츠를 저장하면 개발자가 서로 다른 레코드 또는 레코드 내부의 구조를 사용하여 언어별 대안을 보관하는 방식으로 국제화된 콘텐츠도 저장할 수 있습니다.

API는 API와 상호작용하기 위한 사용자 인터페이스를 사용자 에이전트가 생성하도록 정의하거나 요구하지 않습니다. 사용자 에이전트는 선택적으로 API를 지원하는 사용자 인터페이스 요소를 제공할 수 있습니다. 예로 추가 스토리지 할당량이 필요할 때 사용자에게 표시되는 프롬프트, 특정 웹 사이트가 사용한 스토리지를 확인하는 기능, 레코드 검사·수정·삭제와 같은 API 스토리지 전용 도구가 있습니다. 그러한 사용자 인터페이스 요소는 모두 접근성 도구를 고려하여 설계해야 합니다. 예를 들어 스토리지 할당량 중 사용된 비율을 그래픽 형태로 표시하는 사용자 인터페이스는 화면 읽기 프로그램 같은 도구에도 동일한 데이터를 제공해야 합니다.

11. 개정 이력

이 절은 규범적이지 않습니다.

다음은 이 명세의 마지막 발행 이후 변경 사항을 설명하는 정보 제공용 요약입니다. 전체 개정 이력은 여기에서 확인할 수 있습니다. 초판의 개정 이력은 해당 문서의 개정 이력을 참조하세요. 제2판의 개정 이력은 해당 문서의 개정 이력을 참조하세요.

12. 감사의 말

이 절은 규범적이지 않습니다.

초판의 원저자인 Nikunj Mehta와 초판의 추가 편집자인 Jonas Sicking, Eliot Graff, Andrei Popescu 및 Jeremy Orlow에게 특별히 감사드립니다.

Garret Swart는 이 명세의 설계에 매우 큰 영향을 주었습니다.

이 문서를 만드는 데 사용된 명세 작성 도구인 Bikeshed를 만들고 유지 관리했으며, 전반적인 작성 조언을 제공한 Tab Atkins, Jr.에게 감사드립니다.

특별히 다음 분들께 감사드립니다. Abhishek Shanthkumar, Adam Klein, Addison Phillips, Adrienne Walker, Alec Flett, Andrea Marchesini, Andreas Butler, Andrew Sutherland, Anne van Kesteren, Anthony Ramine, Ari Chivukula, Arun Ranganathan, Ben Dilts, Ben Turner, Bevis Tseng, Boris Zbarsky, Brett Zamir, Chris Anderson, Dana Florescu, Danillo Paiva, David Grogan, Domenic Denicola, Dominique Hazael-Massieux, Evan Stade, Glenn Maynard, Hans Wennborg, Isiah Meadows, Israel Hilerio, Jake Archibald, Jake Drew, Jerome Hode, Josh Matthews, João Eiras, Kagami Sascha Rosylight, Kang-Hao Lu, Kris Zyp, Kristof Degrave, Kyaw Tun, Kyle Huey, Laxminarayan G Kamath A, Maciej Stachowiak, Marcos Cáceres, Margo Seltzer, Marijn Kruisselbrink, Ms2ger, Odin Omdal, Olli Pettay, Pablo Castro, Philip Jägenstedt, Shawn Wilsher, Simon Pieters, Steffen Larssen, Steve Becker, Tobie Langel, Victor Costan, Xiaoqian Wu, Yannic Bonenberger, Yaron Tausky, Yonathan Randolph, 그리고 Zhiqiang Zhang. 이분들의 모든 피드백과 제안 덕분에 이 명세가 개선되었습니다.

적합성

문서 규약

적합성 요구 사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범적 부분에 있는 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” 및 “OPTIONAL”이라는 핵심 단어는 RFC 2119에 설명된 대로 해석해야 합니다. 그러나 가독성을 위해 이 명세에서는 이러한 단어가 모두 대문자로 표시되지는 않습니다.

명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외하고 이 명세의 모든 텍스트는 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 시작되거나 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분됩니다.

이것은 정보 제공용 예제의 예입니다.

정보 제공용 참고는 “참고”라는 단어로 시작하며 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분됩니다.

참고, 이것은 정보 제공용 참고입니다.

적합 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구 사항 (예: "선행 공백 문자를 모두 제거" 또는 "false를 반환하고 이 단계를 중단")은 알고리즘을 도입할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석해야 합니다.

알고리즘 또는 특정 단계로 표현된 적합성 요구 사항은 최종 결과가 동등한 한 어떠한 방식으로든 구현할 수 있습니다. 특히 이 명세에 정의된 알고리즘은 이해하기 쉽도록 작성되었으며 성능을 목적으로 하지 않습니다. 구현자는 최적화하는 것이 권장됩니다.

색인

이 명세에서 정의하는 용어

참조로 정의된 용어

참고 문헌

규범적 참고 문헌

[DOM]
Anne van Kesteren. DOM 표준. 현행 표준. URL: https://dom.spec.whatwg.org/
[ECMA-262]
ECMAScript 언어 명세. URL: https://tc39.es/ecma262/multipage/
[FileAPI]
Marijn Kruisselbrink. File API. 2024년 12월 4일. WD. URL: https://www.w3.org/TR/FileAPI/
[HTML]
Anne van Kesteren; et al. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFC에서 요구 수준을 나타내기 위한 핵심 단어. 1997년 3월. 최선의 현행 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[STORAGE]
Anne van Kesteren. Storage 표준. 현행 표준. URL: https://storage.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

정보 제공용 참고 문헌

[Charmod-Norm]
Addison Phillips; et al. 월드 와이드 웹 문자 모델: 문자열 일치. 2021년 8월 11일. NOTE. URL: https://www.w3.org/TR/charmod-norm/
[COOKIES]
A. Barth. HTTP 상태 관리 메커니즘. 2011년 4월. 제안 표준. URL: https://httpwg.org/specs/rfc6265.html
[WEBSTORAGE]
Ian Hickson. Web Storage (제2판). 2021년 1월 28일. REC. URL: https://www.w3.org/TR/webstorage/

IDL 색인

[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonly attribute any result;
  readonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // Event handlers:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending",
  "done"
};

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};

[Exposed=(Window,Worker)]
interface IDBVersionChangeEvent : Event {
  constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict = {});
  readonly attribute unsigned long long oldVersion;
  readonly attribute unsigned long long? newVersion;
};

dictionary IDBVersionChangeEventInit : EventInit {
  unsigned long long oldVersion = 0;
  unsigned long long? newVersion = null;
};

partial interface mixin WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};

[Exposed=(Window,Worker)]
interface IDBFactory {
  [NewObject] IDBOpenDBRequest open(DOMString name,
                                    optional [EnforceRange] unsigned long long version);
  [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);

  Promise<sequence<IDBDatabaseInfo>> databases();

  short cmp(any first, any second);
};

dictionary IDBDatabaseInfo {
  DOMString name;
  unsigned long long version;
};

[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
  readonly attribute DOMString name;
  readonly attribute unsigned long long version;
  readonly attribute DOMStringList objectStoreNames;

  [NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
                                         optional IDBTransactionMode mode = "readonly",
                                         optional IDBTransactionOptions options = {});
  undefined close();

  [NewObject] IDBObjectStore createObjectStore(
    DOMString name,
    optional IDBObjectStoreParameters options = {});
  undefined deleteObjectStore(DOMString name);

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler onclose;
  attribute EventHandler onerror;
  attribute EventHandler onversionchange;
};

enum IDBTransactionDurability { "default", "strict", "relaxed" };

dictionary IDBTransactionOptions {
  IDBTransactionDurability durability = "default";
};

dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};

[Exposed=(Window,Worker)]
interface IDBObjectStore {
  attribute DOMString name;
  readonly attribute any keyPath;
  readonly attribute DOMStringList indexNames;
  [SameObject] readonly attribute IDBTransaction transaction;
  readonly attribute boolean autoIncrement;

  [NewObject] IDBRequest put(any value, optional any key);
  [NewObject] IDBRequest add(any value, optional any key);
  [NewObject] IDBRequest delete(any query);
  [NewObject] IDBRequest clear();
  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any queryOrOptions,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");

  IDBIndex index(DOMString name);

  [NewObject] IDBIndex createIndex(DOMString name,
                                   (DOMString or sequence<DOMString>) keyPath,
                                   optional IDBIndexParameters options = {});
  undefined deleteIndex(DOMString name);
};

dictionary IDBIndexParameters {
  boolean unique = false;
  boolean multiEntry = false;
};

dictionary IDBGetAllOptions {
  any query = null;
  [EnforceRange] unsigned long count;
  IDBCursorDirection direction = "next";
};

[Exposed=(Window,Worker)]
interface IDBIndex {
  attribute DOMString name;
  [SameObject] readonly attribute IDBObjectStore objectStore;
  readonly attribute any keyPath;
  readonly attribute boolean multiEntry;
  readonly attribute boolean unique;

  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any queryOrOptions,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any queryOrOptions,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllRecords(optional IDBGetAllOptions options = {});
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");
};

[Exposed=(Window,Worker)]
interface IDBKeyRange {
  readonly attribute any lower;
  readonly attribute any upper;
  readonly attribute boolean lowerOpen;
  readonly attribute boolean upperOpen;

  // Static construction methods:
  [NewObject] static IDBKeyRange only(any value);
  [NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false);
  [NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false);
  [NewObject] static IDBKeyRange bound(any lower,
                                       any upper,
                                       optional boolean lowerOpen = false,
                                       optional boolean upperOpen = false);

  boolean includes(any key);
};

[Exposed=(Window,Worker)]
interface IDBRecord {
  readonly attribute any key;
  readonly attribute any primaryKey;
  readonly attribute any value;
};

[Exposed=(Window,Worker)]
interface IDBCursor {
  readonly attribute (IDBObjectStore or IDBIndex) source;
  readonly attribute IDBCursorDirection direction;
  readonly attribute any key;
  readonly attribute any primaryKey;
  [SameObject] readonly attribute IDBRequest request;

  undefined advance([EnforceRange] unsigned long count);
  undefined continue(optional any key);
  undefined continuePrimaryKey(any key, any primaryKey);

  [NewObject] IDBRequest update(any value);
  [NewObject] IDBRequest delete();
};

enum IDBCursorDirection {
  "next",
  "nextunique",
  "prev",
  "prevunique"
};

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};

[Exposed=(Window,Worker)]
interface IDBTransaction : EventTarget {
  readonly attribute DOMStringList objectStoreNames;
  readonly attribute IDBTransactionMode mode;
  readonly attribute IDBTransactionDurability durability;
  [SameObject] readonly attribute IDBDatabase db;
  readonly attribute DOMException? error;

  IDBObjectStore objectStore(DOMString name);
  undefined commit();
  undefined abort();

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler oncomplete;
  attribute EventHandler onerror;
};

enum IDBTransactionMode {
  "readonly",
  "readwrite",
  "versionchange"
};

✔MDN

IDBCursor/advance

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/continue

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/continuePrimaryKey

In all current engines.

Firefox10+Safari10.1+Chrome58+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android51+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/delete

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/direction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/key

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/primaryKey

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/request

In all current engines.

Firefox77+Safari15+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/source

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor/update

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursor

In all current engines.

Firefox16+Safari8+Chrome24+
Opera44+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile43+
✔MDN

IDBCursorWithValue/value

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBCursorWithValue

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBDatabase/close

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/close_event

In all current engines.

Firefox50+Safari10.1+Chrome30+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/close_event

In all current engines.

Firefox50+Safari10.1+Chrome30+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/createObjectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/deleteObjectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/objectStoreNames

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/version

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/versionchange_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase/versionchange_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBDatabase

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBFactory/cmp

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBFactory/databases

FirefoxNoneSafari14+Chrome72+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBFactory/deleteDatabase

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBFactory/open

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBFactory

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBIndex/count

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/get

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/getAll

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/getAllKeys

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/getKey

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/keyPath

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/multiEntry

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/objectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/openCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/openKeyCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex/unique

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBIndex

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBKeyRange/bound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/includes

In all current engines.

Firefox47+Safari10.1+Chrome52+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/lower

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/lowerBound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/lowerOpen

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/only_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/upper

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/upperBound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange/upperOpen

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBKeyRange

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBObjectStore/add

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/autoIncrement

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)?IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/clear

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/count

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/createIndex

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/delete

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/deleteIndex

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/get

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/getAll

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/getAllKeys

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/getKey

In all current engines.

Firefox51+Safari10.1+Chrome48+
Opera45+Edge79+
Edge (Legacy)?IENone
Firefox for Android58+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile43+
✔MDN

IDBObjectStore/index

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/indexNames

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/keyPath

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/openCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/openKeyCursor

In all current engines.

Firefox44+Safari10.1+Chrome23+
Opera?Edge79+
Edge (Legacy)?IE10+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/put

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBObjectStore

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBOpenDBRequest/blocked_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBOpenDBRequest/upgradeneeded_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBOpenDBRequest

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBRequest/error

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/error_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

IDBTransaction/error_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/readyState

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/result

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/source

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/success_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBRequest

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android25+Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBTransaction/abort

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/abort_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/commit

In all current engines.

Firefox74+Safari15+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/complete_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/db

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/durability

FirefoxNoneSafari15+Chrome83+
Opera70+Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/error

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/mode

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/objectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction/objectStoreNames

In all current engines.

Firefox10+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBTransaction

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
✔MDN

IDBVersionChangeEvent/IDBVersionChangeEvent

In all current engines.

Firefox25+Safari10+Chrome41+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBVersionChangeEvent/newVersion

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBVersionChangeEvent/oldVersion

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
✔MDN

IDBVersionChangeEvent

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile?
✔MDN

indexedDB

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?