用了 localStorage,上線后直接崩潰了......
Hello,大家好,我是 Sunday。
在前端開發中,有一個 API 幾乎是所有同學都會經常使用的,那就是:localStorage。
無論是存儲用戶的 Token,還是保存一個 主題色、語言類型,使用 localStorage 都是大家最順手的方案了。
但是,咱們需要知道的是 localStorage 的使用可不是無限制的。
有同學濫用 localStorage ,在項目上線后就會遇到:頁面卡死、一大片報錯的情況。。。
一些 localStorage 報錯的真實場景
1. 存儲超限
localStorage 在瀏覽器里并不是“無限存儲空間”,多數瀏覽器的限制大概在 5MB 左右(不同的瀏覽器存儲限制會有所不同)。
在開發過程中,我們如果只存一些:token、主題配置,那么是沒什么問題的。
但是,如果一旦把負責的用戶數據(比如:用戶對象的序列化數據、頭像的 base64 數據 等等的)保存到 localStorage 的話,就可能會出現 超出上限 的問題。
當調用 setItem 超過上限時,瀏覽器直接拋異常:
Uncaught DOMException: Failed to execute 'setItem' on 'Storage'如果你沒有在代碼里做異常處理,頁面邏輯會 當場中斷。
用戶的直觀體驗就是:頁面打不開、按鈕點不了、甚至閃退。
2. 阻塞主線程
很多同學可能沒注意過:localStorage 這個 API 它是 同步的。
換句話說,每一次 getItem、setItem,都會阻塞整個 JavaScript 主線程。
在輕量場景下也許無感,但在復雜業務場景下可能就會導致卡頓的情況。比如:
- 在循環里頻繁讀寫 localStorage;
- 寫入大體量 JSON(比如上百 KB);
- 在動畫、滾動等高頻操作里調用。
結果就是:頁面直接卡頓。
尤其是在中低端手機上,用戶會明顯感覺頁面“頓了一下”,甚至滑不動。
3. 多標簽頁同步可能會導致數據混亂
localStorage 有一個特性:當一個標簽頁寫入數據時,其他標簽頁會觸發 storage 事件。
聽起來很方便,但很多開發者沒注意處理邊界情況:
- A 標簽頁寫入了一條數據;
- B 標簽頁監聽到
storage事件,又回寫了一條;
結果就是循環觸發,形成 “數據風暴”。
常見場景有:
- 用戶在 A 頁修改了資料,B 頁卻顯示不一致;
- 多個標簽頁同時更新,數據來回覆蓋,用戶完全不知道哪一個才是準的。
這就是 localStorage 的同步廣播機制 沒處理好的典型坑。
4. 明文存儲
這是一個特別容易倍忽視的問題:localStorage 的數據完全是明文的。
打開瀏覽器 DevTools → Application → Storage → Local Storage,你會發現:所有數據都一覽無余 的。
這就意味著:如果你把 Token 存在 localStorage,任何第三方腳本都能讀到
那么,一旦項目存在 XSS 漏洞,攻擊者就能輕松獲取用戶的敏感信息。同時,如果在公共電腦上,用戶登錄后不清理 localStorage,下一個人直接就能冒用身份。
終極解決方案
既然 localStorage 有這么多坑,那我們就要思考:不同場景下,有沒有更好的替代方案?
答案肯定是 有的,甚至瀏覽器已經幫我們準備好了。
下面咱們從常見的四類場景,給出對應的解決方案:
1. 臨時數據存儲:用 sessionStorage
場景:
- 保存頁面臨時狀態(比如搜索條件、當前頁碼);
- 用戶刷新頁面需要保留,但關閉 Tab 就清除。
為什么比 localStorage 好?
- 生命周期綁定在當前 Tab,不會污染其他頁面;
- 數據不會長期堆積,更安全。
示例:
// 存儲
sessionStorage.setItem('filter', JSON.stringify({ keyword: 'vue3' }))
// 獲取
const filter = JSON.parse(sessionStorage.getItem('filter'))2. 大量數據存儲:用 IndexedDB
場景:
- PWA 離線緩存;
- 存儲用戶的草稿、聊天記錄;
- 需要上百 KB 甚至 MB 的數據存儲。
為什么比 localStorage 好?
- 異步 API,不會阻塞主線程;
- 存儲空間大,理論上可達上百 MB;
- 支持事務,保證數據一致性。
示例:
const request = indexedDB.open('myDB', 1)
request.onupgradeneeded = (event) => {
const db = event.target.result
db.createObjectStore('users', { keyPath: 'id' })
}
request.onsuccess = (event) => {
const db = event.target.result
const tx = db.transaction('users', 'readwrite')
const store = tx.objectStore('users')
store.put({ id: 1, name: 'Sunday' })
}3. 跨標簽頁通信:用 BroadcastChannel / SharedWorker
場景:
- 多個 Tab 需要共享登錄狀態;
- 實時同步用戶操作,比如購物車、播放進度。
為什么比 localStorage 好?
- 專門為跨標簽通信設計;
- 不會有 localStorage 的循環觸發問題。
示例:
const channel = new BroadcastChannel('user_channel')
// A 頁發送
channel.postMessage({ login: true })
// B 頁接收
channel.onmessage = (event) => {
console.log('收到消息', event.data)
}4. 敏感數據存儲:用 Cookie + HttpOnly
場景:
- 存儲用戶的登錄憑證(SessionID / Token);
- 與服務端通信時自動帶上。
為什么比 localStorage 好?
- 配置
HttpOnly后,前端 JS 無法讀取,避免被 XSS 攻擊竊取; - 可以加上
Secure屬性,只在 HTTPS 下傳輸; - 更符合認證體系的設計規范。
示例(服務端設置 Cookie):
Set-Cookie: token=abc123; HttpOnly; Secure; SameSite=Strict給大家一個整理好的表格,大家可以作為參考哈































