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

localStorage vs sessionStorage

ความแตกต่างที่สำคัญที่สุดระหว่าง store ทั้งสองคือข้อมูลอยู่ได้นานแค่ไหน:

localStorage

  • ข้อมูลอยู่ถาวรจนกว่าจะถูกลบอย่างชัดเจนด้วย removeItem หรือ clear หรือผู้ใช้ล้างข้อมูล browser
  • การปิดทุกแท็บ ปิด browser หรือรีสตาร์ทเครื่อง ไม่ ทำให้ข้อมูลหายไป
  • จึงเหมาะกับ preferences, ธีม หรือค่าที่ cache ไว้ซึ่งควรอยู่รอดข้าม session (เช่น ปุ่มสลับ dark mode, ภาษาที่บันทึกไว้)

sessionStorage

  • ข้อมูลอยู่เฉพาะตลอดอายุของแท็บ browser (หรือหน้าต่าง) ที่ถูกสร้างขึ้นเท่านั้น
  • ทันทีที่แท็บนั้นถูกปิด ข้อมูลก็หายไป — กู้คืนไม่ได้
  • การเปิดแท็บใหม่ไปยัง URL เดิมจะเริ่มต้นด้วย sessionStorage ที่ว่างเปล่าใหม่
  • จึงเหมาะกับ state เฉพาะแท็บที่ไม่ควรรั่วข้ามแท็บ (เช่น ขั้นตอนปัจจุบันของ wizard หลายขั้น, token แบบใช้ครั้งเดียว, ฉบับร่างฟอร์มชั่วคราว)

ขอบเขตคือจุดที่ API ทั้งสองต่างกันอย่างละเอียดอ่อนที่สุด:

// Tab A:
localStorage.setItem('demo:user', 'Ada');
// Tab B on the same origin sees 'Ada' immediately.
sessionStorage.setItem('demo:step', '2');
// Tab B has its OWN sessionStorage — it cannot see Tab A's 'step'.

มีรายละเอียดปลีกย่อยอยู่อย่างหนึ่ง: เมื่อผู้ใช้เปิดลิงก์ด้วย window.open() หรือ Ctrl+click (ซึ่งทำสำเนาแท็บ) แท็บใหม่จะได้รับ สำเนา ของ sessionStorage จากแท็บแม่ ณ ขณะที่ถูกเปิดขึ้น หลังจากนั้น store ทั้งสองจะเป็นอิสระต่อกัน — การเปลี่ยนแปลงในตัวหนึ่งจะไม่ส่งผลต่ออีกตัว

store ทั้งสองมีขอบเขตตาม origin: scheme + hostname + port

URLOrigin
https://example.comhttps://example.com:443
https://app.example.comhttps://app.example.com:443 (ต่างกัน!)
http://example.comhttp://example.com:80 (ต่าง scheme!)
https://example.com:8080https://example.com:8080 (ต่าง port!)

ดังนั้น https://app.example.com และ https://api.example.com ต่างก็มี localStorage ของตัวเองที่แยกขาดจากกันโดยสิ้นเชิง แม้ว่าจะใช้ registrable domain เดียวกันก็ตาม

รันโค้ดด้านล่างเพื่อดูทั้งสอง store ถูกเขียนและอ่านกลับมาภายใน context ของหน้าเดียวกัน

Browser Storage
ตัวเลือกBenefitCost
localStorageข้อมูลอยู่ถาวรและแชร์ข้ามทุกแท็บของ origin เดียวกัน เหมาะกับ preference ระยะยาวเขียนจากแท็บไหนก็กระทบทุกแท็บ เสี่ยงต่อ race condition หากหลายแท็บเขียนพร้อมกัน
sessionStorageขอบเขตแคบแค่แท็บเดียว ลดความเสี่ยงของข้อมูลรั่วข้ามแท็บ และหายไปเองเมื่อปิดแท็บต้องตั้งค่าใหม่ทุกครั้งที่เปิดแท็บใหม่ ใช้เก็บ preference ระยะยาวไม่ได้
แชร์ state ผ่าน sessionStorage ตอนทำสำเนาแท็บแท็บใหม่ได้ context เดิมทันทีตอนเปิดขึ้นมา (เช่น ทำสำเนากลางฟอร์ม)เป็นสำเนาแบบครั้งเดียว หลังจากนั้น sync กันเองไม่ได้อีก อาจทำให้ข้อมูลสองแท็บ diverge
  • คิดว่า sessionStorage sync กันข้ามแท็บเหมือน localStorage — แต่ละแท็บมี sessionStorage แยกเป็นของตัวเอง เขียนใน Tab A จะไม่มีทางเห็นใน Tab B
  • เก็บ auth token ใน localStorage — เพราะ JavaScript อ่านได้โดยตรง หาก origin โดน XSS token จะถูกขโมยได้ง่าย ต่างจาก HttpOnly cookie ที่ JS แตะไม่ถึง
  • สับสนระหว่าง subdomain กับ origin เดียวกันapp.example.com และ api.example.com มี localStorage แยกกันคนละก้อนเสมอ แม้ registrable domain จะเหมือนกัน

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

Theme/dark-mode toggle — เว็บส่วนใหญ่เก็บค่า preference นี้ด้วย localStorage เพราะต้องการให้ค่าคงอยู่ข้าม session และแชร์ทุกแท็บที่เปิดพร้อมกัน

Multi-step checkout wizard — เว็บอีคอมเมิร์ซใช้ sessionStorage เก็บ step ปัจจุบันและข้อมูลฟอร์มระหว่างทาง เพื่อไม่ให้ข้อมูลนี้รั่วไปยังแท็บอื่นหรือค้างอยู่หลังผู้ใช้ปิดแท็บไปแล้ว

คุณเปิด Tab A แล้วเรียก sessionStorage.setItem("x", "1") จากนั้นเปิด Tab B ไปยัง URL เดียวกัน sessionStorage.getItem("x") ใน Tab B จะคืนค่าอะไร?
ผู้ใช้ตั้งค่า dark-mode preference store ตัวไหนเหมาะสมที่สุดเพื่อให้ค่านี้อยู่รอดหลังจากปิดและเปิด browser ใหม่?
https://shop.example.com และ https://blog.example.com ใช้ localStorage เดียวกันหรือไม่?
เมื่อผู้ใช้ทำสำเนาแท็บ (Ctrl+click ที่ลิงก์) จะเกิดอะไรขึ้นกับ sessionStorage?