TypeScript และ StorageManager
บทความนี้อธิบายเกี่ยวกับ TypeScript และ StorageManager
เรามีตัวอย่างการใช้งานจริงเพื่ออธิบายเกี่ยวกับ TypeScript และ StorageManager
YouTube Video
TypeScript และ StorageManager
StorageManager คืออะไร?
StorageManager เป็น API ที่ช่วยให้เว็บแอปพลิเคชันสามารถประเมินการใช้งานพื้นที่จัดเก็บและความจุที่ยังเหลืออยู่ได้ นอกจากนี้ ยังมีฟังก์ชัน persist (persist()) ที่ช่วยป้องกันไม่ให้ข้อมูลถูกลบโดยอัตโนมัติจากผู้ใช้หรือเบราว์เซอร์ คุณจึงสามารถควบคุมได้ว่ามีพื้นที่ว่างเพียงพอหรือไม่ หรือข้อมูลจะถูกลบโดยอัตโนมัติ เช่น การเก็บข้อมูลจำนวนมากใน IndexedDB สำหรับแอปพลิเคชันออฟไลน์
การตรวจจับฟีเจอร์
ขั้นแรก ตรวจสอบว่าเบราว์เซอร์รองรับ navigator.storage หรือไม่
1// TypeScript: feature detection for StorageManager
2function supportsStorageManager(): boolean {
3 return typeof navigator !== "undefined" &&
4 typeof navigator.storage !== "undefined" &&
5 typeof navigator.storage.estimate === "function";
6}
7
8// Example usage
9if (supportsStorageManager()) {
10 console.log("StorageManager is supported.");
11} else {
12 console.warn("StorageManager not supported. Falling back to localStorage or IndexedDB.");
13}- ฟังก์ชันนี้จะตรวจสอบการใช้งานของ StorageManager API เป็นลำดับขั้น
- เนื่องจาก
navigator.storageไม่มีอยู่ในบางเบราว์เซอร์เช่น Safari จึงควรตรวจสอบอย่างปลอดภัยด้วยtypeof
การประเมินการใช้พื้นที่จัดเก็บ (estimate())
หลังจากตรวจสอบความสามารถในการใช้งานด้วย supportsStorageManager() ให้ดึงข้อมูลการใช้งาน (usage) และโควตา (quota) จาก navigator.storage.estimate()
1// TypeScript: safely get storage estimate
2async function getStorageEstimate(): Promise<{ usage: number; quota: number } | null> {
3 if (!supportsStorageManager()) {
4 console.warn("StorageManager not supported.");
5 return null;
6 }
7
8 const estimate = await navigator.storage.estimate();
9 return { usage: estimate.usage ?? 0, quota: estimate.quota ?? 0 };
10}
11
12// Example usage
13getStorageEstimate().then(result => {
14 if (result) {
15 console.log(`Usage: ${result.usage} bytes / Quota: ${result.quota} bytes`);
16 }
17});- ฟังก์ชันนี้ทำงานอย่างปลอดภัยเสมอ และจะคืนค่าเป็น
nullหากเบราว์เซอร์ไม่รองรับ usageและquotaเป็นค่าประมาณการณ์และอาจแตกต่างกันไปในแต่ละเบราว์เซอร์
การร้องขอให้ข้อมูลคงอยู่ (persist())
ใช้ persist() เพื่อขอให้ข้อมูลสำคัญ (เช่น cache สำหรับออฟไลน์) ไม่ถูกลบโดยอัตโนมัติจากเบราว์เซอร์ แต่อาจไม่สำเร็จในทุกสภาพแวดล้อม
1// TypeScript: safely request persistent storage
2async function requestPersistence(): Promise<boolean> {
3 if (!supportsStorageManager()) {
4 console.warn("StorageManager not supported.");
5 return false;
6 }
7
8 if (typeof navigator.storage.persist !== "function") {
9 console.warn("persist() not available in this browser.");
10 return false;
11 }
12
13 try {
14 const granted = await navigator.storage.persist();
15 return Boolean(granted);
16 } catch (err) {
17 console.error("persist() error:", err);
18 return false;
19 }
20}
21
22// Example usage
23requestPersistence().then(granted => {
24 console.log("Persistence granted?", granted);
25});- หาก
persist()สำเร็จ ข้อมูลจะไม่ถูกลบโดยอัตโนมัติจากเบราว์เซอร์ ยกเว้นผู้ใช้จะลบเอง อย่างไรก็ตาม คำขออาจถูกปฏิเสธขึ้นอยู่กับการกระทำของผู้ใช้หรือการตั้งค่าเบราว์เซอร์
ตรวจสอบพื้นที่ว่างก่อนบันทึกข้อมูล
ตรวจสอบพื้นที่ว่างก่อนบันทึกข้อมูลขนาดใหญ่เพื่อป้องกันข้อผิดพลาดขณะเขียนข้อมูล (QuotaExceededError)
1// TypeScript: ensure enough space before writing
2async function ensureSpaceAndWrite(neededBytes: number, writeFn: () => Promise<void>): Promise<boolean> {
3 const estimate = await getStorageEstimate();
4 if (!estimate) {
5 console.warn("Cannot check storage space. Proceeding without validation.");
6 await writeFn();
7 return true;
8 }
9
10 const free = estimate.quota - estimate.usage;
11 if (free < neededBytes) {
12 console.warn(`Not enough space. Free: ${free} bytes, needed: ${neededBytes} bytes.`);
13 return false;
14 }
15
16 await writeFn();
17 return true;
18}
19
20// Example usage
21ensureSpaceAndWrite(10 * 1024 * 1024, async () => {
22 console.log("Saving large data...");
23});- การตรวจสอบพื้นที่ว่างก่อนบันทึก ช่วยลดความเสี่ยงจากการเขียนข้อมูลล้มเหลวเนื่องจากพื้นที่ไม่เพียงพอ
การจัดการ localStorage แบบ type-safe ใน TypeScript
localStorage เหมาะกับการเก็บข้อมูลการตั้งค่าขนาดเล็กและข้อมูลที่คล้ายกัน
คลาสด้านล่างนี้ใช้ generics เพื่อสร้าง wrapper ที่ type-safe
1// TypeScript: typed localStorage wrapper
2type Serializer<T> = {
3 serialize: (v: T) => string;
4 deserialize: (s: string) => T;
5};
6
7class TypedLocalStorage<K extends string, V> {
8 constructor(private storage: Storage, private serializer: Serializer<V>) {}
9
10 set(key: K, value: V): void {
11 this.storage.setItem(key, this.serializer.serialize(value));
12 }
13
14 get(key: K): V | null {
15 const raw = this.storage.getItem(key);
16 if (raw === null) return null;
17 try {
18 return this.serializer.deserialize(raw);
19 } catch {
20 return null;
21 }
22 }
23
24 remove(key: K): void {
25 this.storage.removeItem(key);
26 }
27
28 clear(): void {
29 this.storage.clear();
30 }
31}
32
33// Example usage
34const jsonSerializer: Serializer<any> = {
35 serialize: v => JSON.stringify(v),
36 deserialize: s => JSON.parse(s),
37};
38
39const appStorage = new TypedLocalStorage<'theme' | 'token', any>(localStorage, jsonSerializer);
40appStorage.set('theme', { dark: true });
41console.log(appStorage.get('theme'));- คลาสนี้ช่วยลดความเสี่ยงจากการเก็บหรือเรียกข้อมูลผิดประเภท
ข้อควรพิจารณาและแนวปฏิบัติที่ดี
-
ควรตรวจสอบว่าเบราว์เซอร์รองรับ StorageManager อยู่เสมอ เนื่องจาก StorageManager เป็น API ใหม่เสมอ ควรตรวจสอบการมีอยู่ก่อนใช้งานทุกครั้ง
-
ควรใส่ใจกับข้อจำกัดและความเข้ากันได้ของพื้นที่จัดเก็บ ค่าที่ได้จาก
estimate()แตกต่างกันไปในแต่ละเบราว์เซอร์และเป็นเพียงค่าประมาณการณ์ -
ออกแบบโดยคำนึงถึงการทำงานแบบอะซิงโครนัสของ API
estimate()และpersist()เป็น API แบบอะซิงโครนัสที่ใช้ Promise เขียนโค้ดให้ UI ไม่ถูกบล็อกจากการทำงานของ API เหล่านี้ -
เรื่องความปลอดภัย ไม่ควรเก็บข้อมูลสำคัญ เช่น access token ไว้ใน
localStorageควรใช้ HttpOnly cookies หรือการเข้ารหัสแทน หากเป็นไปได้ -
การออกแบบ fallback หาก
supportsStorageManager()คืนค่า false ควรเพิ่มตรรกะเพื่อเปลี่ยนไปใช้เพียงlocalStorageหรือIndexedDBเท่านั้น
สรุป
ด้วยการตรวจจับฟีเจอร์ด้วย supportsStorageManager() คุณสามารถรองรับทุกสภาพแวดล้อมได้อย่างปลอดภัย พร้อมทั้งตรวจสอบการใช้งานและโควต้าผ่าน navigator.storage.estimate() และร้องขอการคงอยู่ของข้อมูลด้วย persist() ใน TypeScript ควรใช้ฟังก์ชัน wrapper และกำหนด type เพื่อให้โค้ดอ่านง่ายและปลอดภัย โดยลำดับพื้นฐานคือ: ตรวจสอบการมีอยู่, ประเมิน, ร้องขอการคงอยู่, และตรวจสอบความจุก่อนบันทึกข้อมูล
คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย