냐냐한 IT/냐냐한 실습 기록

IndexedDB API: IndexedDB 사용 - 4 (버전 변경 시 다른 탭, 보안, 브라우저 종료 시 경고 등 나머지 내용)

소소하냐 2022. 11. 14. 10:26
MDN 원문 참조 : https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#version_changes_while_a_web_app_is_open_in_another_tab 
날짜 : 2022.11.14 (문서 내용은 계속 변경되는 부분이라 정리한 날짜를 함께 기록)

위 참조 링크 내용을 정리하였습니다.  


다른 탭에 웹 응용프로그램이 열려있을 때 버전 변경 (Version changes while a web app is open in another tab)

- 데이터베이스 버전 변경 시, 이전 버전이 다른 탭에 열려 있을 경우 

   : 데이터베이스는 변경이 일어나기 전에 요청을 명시적으로 확인함 (onblocked 이벤트는 탭이 닫히거나 다시 로드될때까지 발생함)

const openReq = mozIndexedDB.open("MyTestDatabase", 2);

openReq.onblocked = (event) => {
  // 데이터베이스가 다른 탭에 열려있으면, 진행하기 전에 닫아야 함
  console.log("이 사이트가 열려있는 다른 모든 탭을 닫으십시오!");
};

openReq.onupgradeneeded = (event) => {
  // 다른 모든 데이터베이스 닫음. 모든 것을 설정 
  db.createObjectStore(/* … */);
  useDatabase(db);
};

openReq.onsuccess = (event) => {
  const db = event.target.result;
  useDatabase(db);
  return;
};

function useDatabase(db) {
  // 다른 페이지에서 버전 변경 요청을 하는 경우 알림을 받을 핸들러를 추가해야 함 
  // 데이터베이스를 닫아야 함. 이렇게 하면 다른 페이지에서 데이터베이스 엡그레이드가 가능
  // 이렇게 하지 않으면 사용자가 탭을 닫을 때까지 업그레이드가 일어나지 않음. 
  db.onversionchange = (event) => {
    db.close();    
    console.log("이 페이지의 새 버전이 준비되었습니다. 이 탭을 다시 로드하거나 닫으세요!");
  };

  // 작업
}

 

- 이미 열려있는 사이트가 데이터베이스를 열려는 새로운 시도 코드를 시작할 수 있지만, 구 버전을 사용하는 상황을 처리하기 위해 VersionError 오류를 수신해야 함 

  (정리자 해석 : 이미 열려있는 사이트에서 구 버전으로 open 하려고 할 수 있기 때문에, VersionError에 대한 오류 처리가 들어가야 한다?) 

 

정리자 테스트 코드 및 결과 정리(크롬 새 탭 상태에서 콘솔에서 실행함) : 

function openDB(version) {    
    console.log(`-------------- openDB(${version}) --------------`)  
    const request = indexedDB.open("testDBNew", version);
    request.onerror = function (event) {
        console.log("onerror!", event);
    };
    request.onsuccess = function (event) {
        console.log("onsuccess!", event);
        const db = event.target.result;
        useDatabase(db);
        return;
    };
    request.onupgradeneeded = function (event) {
        console.log("onupgradeneeded!", event);
        const db = event.target.result;
        useDatabase(db);
    };
    request.onblocked = function (event) {
      console.log("onblocked!", event);
      alert("이 사이트가 열려있는 다른 모든 탭을 닫으십시오!");
  };
}

function useDatabase(db) {
    db.onversionchange = (event) => {
      console.log("db.onversionchange!");
      alert("이 페이지의 새 버전이 준비되었습니다. 이 탭을 다시 로드하거나 닫으세요!");
    };
  }

좌측 상하단) 얼럿 [확인] 누르기 전, 우측 상하단) 얼럿 [확인] 누른 후

위 결과 설명 : 

1. 버전 1 탭에서 openDB(1) => "testDBNew" 버전 1 오픈함 

2. 버전 2 탭에서 openDB(2) => "testDBNew" 버전 1이 다른 탭에서 열려있는 상태에서 버전 2를 오픈함 

3. (버전 2 탭에서 실행했지만) 버전 1 탭에서 onversionchange 이벤트가 발생하고, 설정된 얼럿이 발생 

4. 위 얼럿에서 [확인]  

5. 버전 2 탭에서 onblocked 이벤트가 발생하고, 설정된 얼럿이 발생 

보안 (Security)

- IndexedDB는 동일 출처 정책을 사용 

   (store가 생성된 사이트(일반적으로 사이트 도메인 또는 서브도메인)에 연결되어 있음을 의미. 따라서 다른 출처에서의 접근은 불가능)

 

- 브라우저가 third party 쿠키를 허용하지 않으면 third party window content(예: <iframe>)가 indexedDB에 액세스 불가(bug 1147821 확인). 

 

브라우저 종료에 대한 경고 (Warning about browser shutdown)

- (사용자가 종료, 종료 옵션을 선택하는 등의 이유로) 브라우저가 종료되고, 데이터베이스가 포함된 디스크가 예상치 못하게 제거되거나 데이터베이스 저장소에 대한 권한을 잃게 되는 경우 : 

 

   1. 영향받는 모든 데이터베이스(또는 브라우저 종료 시에 열린 모든 데이터베이스)의 각 트랜잭션은 AbortError로 중지됨.

        (각 트랜잭션에서 IDBTransaction.abort()가 호출되는 것과 같은 효과)

   2. 모든 트랜잭션이 완료되면, 데이터베이스 연결이 닫힘(close). 

   3. 최종적으로, 데이터베이스 연결을 나타내는 IDBDatabase 객체는 close 이벤트를 받음. IDBDatabase.onclose 이벤트 처리기를 사용하여 데이터베이스의 예상치 못한 종료를 알 수 있다

- 위 내용은 새로운 것으로, 다음의 브라우저 릴리즈에서만 사용 가능 : Firefox 50, Google Chrome 31 (대략) 

- 이전 브라우저 버전은, 트랜잭션이 조용히 중지되었고, close 이벤트가 발생하지 않았으므로 예상치 못한 데이터베이스 종료를 탐지할 방법이 없다.  

 

(작성자 덧, 아래 내용은 요약이 힘들어 서술된 내용 그대로 둡니다.) 

 

사용자는 언제든지 브라우저를 종료할 수 있기 때문에, 이는 특정 트랜잭션이 완료되는 것에 의존할 수다는 것을 의미하며, 오래된 브라우저는, 완료되지 않았을 때조차 알려주지 않습니다. 이 동작에는 몇 가지 의미가 있습니다. 

 

첫째, 모든 트랜잭션이 끝날 때 항상 데이터베이스를 일관된 상태로 유지하도록 주의해야 합니다. 예를 들면, 사용자가 편집할 수 있는 항목의 목록을 저장하기 위해 IndexedDB를 사용한다고 가정합니다. object sotre를 지운 다음 새 목록을 작성하여 편집 후 목록을 저장합니다. 한 트랜잭션에서 object store를 지우고 다른 트랜잭션에서 새 목록을 작성하려는 경우 지운 후 쓰기 전에 브라우저가 닫혀 빈 데이터베이스가 남을 위험이 있습니다. 이를 피하려면, 지우기와 쓰기를 단일 트랜잭션으로 결합해야 합니다. 

 

둘째, unload 이벤트에 데이터베이스 트랜잭션을 연결해서는 안 됩니다. 브라우저 종료로 unload 이벤트가 발생하면, unload 이벤트 처리기에서 생성된 모든 트랜잭션은 절대 완료되지 않습니다. 브라우저 세션 간 정보를 유지하기 위한 직관적인 접근 방식은 브라우저(또는 특정 페이지)가 열렸을 때 데이터베이스에서 읽고, 사용자가 브라우저와 상호작용 시 업데이트한 다음, 브라우저(또는 페이지)가 닫힐 때 데이터베이스에 저장하는 것입니다. 그러나, 이렇게 동작하지 않습니다. 데이터베이스 트랜잭션은 unload event에서 생성될 거지만, 비동기이기 때문에 실행 전에 중단됩니다. 

 

사실, 정상적인 브라우저 종료라도, IndexedDB 트랜잭션 완료를 보장할 방법은 없습니다. bug 870645 확인. 

정상적인 종료 알림을 위한 해결 방법으로, 트랜잭션을 추적하고 unload 시점에 아직 완료되지 않은 트랜잭션이 있는 경우 사용자에게 경고하는 beforeunload 이벤트를 추가할 수 있습니다. 

 

최소한 중단(abort) 알림과 IDBDatabase.onclose의 추가로, 이러한 일이 발생했을 때 알 수 있습니다. 

 

 

 

 

현지(locale) 인식 정렬 (Locale-aware sorting)

- Mozilla는 Firefox 43 이상에서 구현된 내용 

 

기본적으로, IndexedDB는 정렬할 문자열의 국제화를 전혀 처리하지 않았고, 모든 것이 영어 문자로 정렬되었습니다. 예를 들면, b, á, z, a 는 다음과 같이 정렬됩니다 : a, b, z, á

 

이는 분명히 사용자가 정렬되기 원하는 방식이 아닙니다 — 예를 들어 Aaron과 Áaron은 연락 목록에서 서로 옆에 있어야 합니다. 

따라서 적절한 국제화 정렬은 메모리에서 호출될 전체 데이터셋(dataset)이 요구되고, 클라이언트 측 JavaScript로 정렬이 수행돼야 하므로 그다지 효율적이지 않습니다. 

 

이 새로운 기능은 IDBObjectStore.createIndex()를 사용하여 인덱스를 생성할 때 개발자가 locale을 지정할 수 있게 합니다. 

커서를 사용하여 데이터셋을 반복하고, locale 인식 정렬을 지정하려는 경우, IDBLocaleAwareKeyRange 를 사용할 수 있습니다. 

 

IDBIndex에는 locale이 지정되었는지, 그것이 무엇인지를 지정하기 위해 추가된 새로운 속성이 있습니다 : 

- locale(locale이 있으면 locale을, 또는 지정된 것이 없으면 null을 반환) 

- isAutoLocale (자동 locale로 생성된 index이면 true를 반환, 즉 플랫폼의 기본 locale이 사용되는 것을 의미하며, 그렇지 않으면 false를 반환) 

 

Note : 이 기능은 현재 숨겨져 있습니다 — 이것을 활성화하고 실험하려면, about:confg로 가서 dom.indexedDB.experimental을 활성화해야 합니다. 

 

전체 IndexedDB 예제 (Full IndexedDB example) 

 

IndexedDB API를 사용한 완전한 예제가 있습니다. 이 예제는 발행물을 저장하고 조회하는데 IndexedDB를 사용합니다. 

 

   * 예제 확인

   * 소스 코드 보기 (github)

 


IndexedDB 정리 목록

IndexedDB API: Intro (개요)

IndexedDB API: IndexedDB 사용 - 1 (개요)

IndexedDB API: IndexedDB 사용 - 2 (저장소(store) 생성 및 구조화)

IndexedDB API: IndexedDB 사용 - 3 (데이터 추가, 검색, 제거)

IndexedDB API: IndexedDB 사용 - 4 (버전 변경 시 다른 탭, 보안, 브라우저 종료 시 경고 등 나머지 내용)

IndexedDB API: IndexedDB 주요 특징 및 기본 용어