การเปิด database
การเปิด database ด้วย indexedDB.open()
หัวข้อที่มีชื่อว่า “การเปิด database ด้วย indexedDB.open()”ต่างจาก 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 มีอยู่แล้ว
Event handler ทั้งสาม
หัวข้อที่มีชื่อว่า “Event handler ทั้งสาม”onupgradeneeded
หัวข้อที่มีชื่อว่า “onupgradeneeded”เกิดขึ้นเมื่อสร้าง 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 โดยอัตโนมัติ
onsuccess
หัวข้อที่มีชื่อว่า “onsuccess”เกิดขึ้นหลังจาก onupgradeneeded เสร็จสิ้น (หรือทันทีหากไม่ต้องการ upgrade) database เปิดแล้วและพร้อมใช้งาน
request.onsuccess = (event) => { const db = event.target.result; // IDBDatabase console.log('Opened:', db.name, 'at version', db.version);};onerror
หัวข้อที่มีชื่อว่า “onerror”เกิดขึ้นเมื่อคำขอเปิด database ล้มเหลว — เช่น หาก browser ของผู้ใช้อยู่ในโหมด private ที่มีการบล็อก storage หรือหาก tab อื่นถือ version-change transaction ที่ถูกบล็อก
request.onerror = (event) => { console.error('Failed to open DB:', event.target.error);};Event versionchange
หัวข้อที่มีชื่อว่า “Event versionchange”หลังจาก 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 ในบริบทอื่นจะถูกบล็อกจนกว่าคุณจะปิด
รูปแบบการเปิด database แบบสมบูรณ์
หัวข้อที่มีชื่อว่า “รูปแบบการเปิด database แบบสมบูรณ์”การห่อ 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);ทดลองรัน: เปิด ตรวจสอบ ปิด และทำความสะอาด
หัวข้อที่มีชื่อว่า “ทดลองรัน: เปิด ตรวจสอบ ปิด และทำความสะอาด”ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
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 ตั้งแต่เวอร์ชันแรก