ข้ามไปยังเนื้อหา

การเปิด database

ต่างจาก fetch() ที่คืนค่าเป็น Promise, indexedDB.open(name, version) จะคืนค่าเป็น IDBOpenDBRequest — ไม่ใช่ Promise คุณโต้ตอบกับ request นี้ผ่านการกำหนด callback ให้กับ event handler

const request = indexedDB.open('my-database', 1);

พารามิเตอร์ทั้งสองคือ:

  • name — string ที่ระบุตัวตนของ database ภายใน origin แต่ละ origin มี namespace แยกเป็นอิสระ
  • version — จำนวนเต็มบวก หาก database ยังไม่มีอยู่จะถูกสร้างที่เวอร์ชันนี้ หากมีอยู่แล้วในเวอร์ชันที่ต่ำกว่าจะเกิดการอัปเกรด

การละเว้น version จะใช้ค่าเริ่มต้นเป็นเวอร์ชัน 1 เมื่อสร้างใหม่ หรือเวอร์ชันปัจจุบันหาก database มีอยู่แล้ว

เกิดขึ้นเมื่อสร้าง database เป็นครั้งแรก หรือ เมื่อเวอร์ชันที่ร้องขอสูงกว่าเวอร์ชันที่จัดเก็บไว้ นี่คือที่ที่คุณกำหนด (หรือ migrate) schema — สร้าง object store เพิ่ม index หรือลบ store เก่า

request.onupgradeneeded = (event) => {
const db = event.target.result; // IDBDatabase
// สร้าง object store โดยใช้ 'id' เป็น key path
db.createObjectStore('notes', { keyPath: 'id' });
};

event.target.result (หรือ request.result ภายใน handler) คือ instance ของ IDBDatabase การเปลี่ยนแปลง schema ที่ทำที่นี่ถูกห่อหุ้มด้วย upgrade transaction โดยอัตโนมัติ

เกิดขึ้นหลังจาก onupgradeneeded เสร็จสิ้น (หรือทันทีหากไม่ต้องการ upgrade) database เปิดแล้วและพร้อมใช้งาน

request.onsuccess = (event) => {
const db = event.target.result; // IDBDatabase
console.log('Opened:', db.name, 'at version', db.version);
};

เกิดขึ้นเมื่อคำขอเปิด database ล้มเหลว — เช่น หาก browser ของผู้ใช้อยู่ในโหมด private ที่มีการบล็อก storage หรือหาก tab อื่นถือ version-change transaction ที่ถูกบล็อก

request.onerror = (event) => {
console.error('Failed to open DB:', event.target.error);
};

หลังจาก database เปิดแล้ว instance ของ IDBDatabase ของคุณสามารถรับ event versionchange ได้ สิ่งนี้เกิดขึ้นเมื่อ tab อื่น (หรือหน้าเดิมหลัง reload) เรียก indexedDB.open() ด้วยหมายเลขเวอร์ชันที่ สูงกว่า

db.onversionchange = () => {
db.close(); // ปล่อย connection เพื่อให้การ upgrade ดำเนินต่อได้
alert('Database is outdated. Please reload the page.');
};

หากคุณไม่ปิด connection การ upgrade ในบริบทอื่นจะถูกบล็อกจนกว่าคุณจะปิด

การห่อ API แบบ callback ด้วย Promise ทำให้ใช้ร่วมกับ async/await ได้:

function openDatabase(name, version) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(name, version);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('notes')) {
db.createObjectStore('notes', { keyPath: 'id' });
}
};
request.onsuccess = (event) => {
const db = event.target.result;
db.onversionchange = () => db.close();
resolve(db);
};
request.onerror = (event) => {
reject(event.target.error);
};
});
}
// การใช้งาน
const db = await openDatabase('my-database', 1);
console.log('Ready:', db.name, db.version);
Browser Storage
ตัวเลือกBenefitCost
Async แบบ event-based ของ indexedDB.openไม่ block main thread ระหว่างเปิด database ขนาดใหญ่ต้องเขียน callback สามชั้น (onupgradeneeded, onsuccess, onerror) แทนที่จะ await ตรง ๆ
Version-based schema migrationควบคุม schema เปลี่ยนแปลงได้ชัดเจนผ่าน oldVersion/newVersionต้องออกแบบ migration logic เองทุกครั้งที่เพิ่มเวอร์ชัน และเสี่ยงลืม handle onblocked
wrap open() ด้วย Promiseใช้ async/await เขียนโค้ดเป็นเส้นตรง อ่านง่ายขึ้นมากซ่อนรายละเอียด event lifecycle ไป — debug ยากขึ้นถ้าลืม handle onblocked หรือ onversionchange
  • ไม่ handle event onblocked — ถ้า tab อื่นเปิด connection เดิมค้างอยู่ การ upgrade เวอร์ชันจะค้างเงียบ ๆ โดยไม่มี error ใด ๆ ผู้ใช้จะเห็นหน้าเว็บค้างโดยไม่รู้สาเหตุ
  • ลืมปิด connection ใน onversionchange — ถ้าไม่เรียก db.close() เมื่อ tab อื่นร้องขอ upgrade การ upgrade นั้นจะถูกบล็อกไปเรื่อย ๆ จนกว่า tab นี้จะถูกปิดหรือ reload
  • ไม่ผูก onerror กับ request — เมื่อ open() ล้มเหลว เช่น ใน private mode ที่บล็อก storage error จะหายไปเงียบ ๆ โดยไม่มี log ใด ๆ ให้ debug

💡 ตัวอย่างจากของจริง

Google Docs — ใช้ version number ควบคุม schema ของ object store สำหรับ offline editing และ handle onversionchange เพื่อปิด connection เก่าเมื่อ deploy schema ใหม่ผ่าน tab ที่ reload แล้ว

WhatsApp Web — เปิด database ตอน login ครั้งแรกด้วย indexedDB.open() และใช้ onupgradeneeded สร้าง object store สำหรับ message history และ contact list ตั้งแต่เวอร์ชันแรก

indexedDB.open("myDB", 1) คืนค่าอะไร?
ใน event handler ใดที่คุณต้องเรียก db.createObjectStore()?
Event ใดที่เกิดขึ้นบน IDBDatabase ที่เปิดอยู่ เมื่อบริบทอื่นร้องขอเวอร์ชันที่สูงกว่าของฐานข้อมูลเดียวกัน?