一、UniApp 緩存系統概述
1.1 緩存概念與作用
在 UniApp 中,本地緩存(Storage)是一種鍵值對(Key-Value)存儲機制,用於在設備本地保存小量數據。它類似於瀏覽器的 localStorage 或小程序的 wx.setStorage,但 UniApp 通過統一的 API 封裝,實現了跨平台的透明使用。緩存的作用主要體現在以下方面:
- 性能提升:避免重複網絡請求。例如,登錄後將 Token 存入緩存,下次啓動 App 時直接讀取,無需重新驗證。
- 用户體驗優化:支持離線模式,如緩存文章列表,用户無網也能瀏覽。
- 數據持久化:應用重啓或頁面刷新後,數據不丟失(除非手動清理)。
- 狀態共享:跨頁面/組件共享數據,如購物車內容。
與內存狀態(如 Vuex)不同,緩存是持久化的,但需注意其非關係型特性:不支持複雜查詢,僅適合簡單對象或字符串。在實際項目中,我經常用它來處理臨時配置,避免每次啓動都從服務器拉取。
1.2 平台差異詳解
UniApp 緩存在不同平台的底層實現有所差異,這直接影響存儲上限、持久性和清理策略。以下表格總結關鍵差異:
|
平台
|
底層實現
|
存儲上限
|
持久性
|
清理機制
|
|
H5 |
localStorage
|
約 5MB(瀏覽器限制)
|
緩存概念,可能被瀏覽器清理
|
用户清除瀏覽數據或過期
|
|
App |
plus.storage
|
無限制(設備存儲空間)
|
持久化,直至卸載 App
|
手動清理或系統空間不足
|
|
微信小程序 |
wx.setStorage
|
單 key 1MB,總 10MB
|
與小程序生命週期綁定
|
用户刪除小程序或超限自動清理
|
|
支付寶小程序 |
my.setStorage
|
單條 200KB,總 10MB
|
與小程序生命週期綁定
|
超限自動清理
|
|
百度/抖音小程序 |
平台特定 API
|
視平台文檔(約 10MB)
|
與小程序生命週期綁定
|
平台策略清理
|
|
HarmonyOS |
分佈式存儲
|
視設備(HBuilderX 4.23+ 支持)
|
持久化
|
手動或系統管理
|
注意:清空緩存後,非 App 平台可能導致 uni.getSystemInfo 的 deviceId 改變,影響設備標識。開發者需在多端測試,確保兼容。在我的經驗中,App 端的無限制存儲特別適合緩存大文件列表,但要警惕設備空間耗盡。
1.3 支持的數據類型與限制
UniApp 緩存支持原生類型(String、Number、Boolean、Array、Object)和可通過 JSON.stringify 序列化的複雜對象。但不支持函數、Date 對象(需轉為字符串)或循環引用。限制包括:
- Key 命名:避免系統保留前綴(如
uni-、dcloud_),否則可能衝突或失敗。 - 數據大小:超出平台上限時,存儲失敗,無自動壓縮。
- 線程安全:異步 API 不阻塞 UI 線程,同步 API 可能在高頻操作時影響性能。
- 生命週期:H5/App 持久,小程序隨應用銷燬。
這些基礎認知是上手的關鍵,接下來我們深入 API 層面。
二、基礎 API 詳解
UniApp 提供 5 對核心 API:存儲、獲取、移除、清空和信息查詢。每對均有異步(回調式)和同步(try-catch 式)版本。異步適合複雜場景,避免阻塞;同步適合簡單操作,代碼簡潔。以下逐一拆解。
2.1 存儲數據:uni.setStorage / uni.setStorageSync
原理:將數據存入指定 key,會覆蓋原有內容。底層序列化為字符串存儲。
異步版本:uni.setStorage(OBJECT)
參數表:
|
參數名
|
類型
|
必填
|
説明
|
|
key
|
String
|
是
|
緩存鍵名,建議使用描述性命名如 ‘user_token’
|
|
data
|
Any
|
是
|
存儲內容,支持 JSON 序列化對象
|
|
success
|
Function
|
否
|
成功回調,無參數
|
|
fail
|
Function
|
否
|
失敗回調,參數為錯誤對象
|
|
complete
|
Function
|
否
|
結束回調,無論成敗
|
返回值:無,通過回調處理。
示例(Vue 頁面中):
// pages/index/index.vue
export default {
methods: {
asyncStoreData() {
uni.setStorage({
key: 'user_info',
data: { id: 1, name: '張三', token: 'abc123' },
success: () => {
console.log('存儲成功');
uni.showToast({ title: '數據已緩存' });
},
fail: (err) => {
console.error('存儲失敗:', err);
uni.showToast({ title: '存儲出錯', icon: 'none' });
}
});
}
}
}
解釋:在按鈕點擊事件中調用,成功後提示用户。data 對象自動序列化。在實際開發中,這種異步方式特別適合用户交互密集的頁面。
同步版本:uni.setStorageSync(key, data)
參數:key (String,必填),data (Any,必填)。
返回值:無,使用 try-catch 處理異常。
示例:
try {
uni.setStorageSync('user_info', { id: 1, name: '張三', token: 'abc123' });
console.log('同步存儲成功');
} catch (e) {
console.error('同步存儲失敗:', e);
}
規則:
- 異步優先:UI 交互場景用異步,避免卡頓。
- 錯誤處理:fail 回調捕獲網絡/權限問題,try-catch 捕獲序列化失敗。
- 注意事項:data 必須可序列化,否則拋錯(如包含函數)。我通常在存儲前添加一個序列化檢查函數,確保穩定性。
2.2 獲取數據:uni.getStorage / uni.getStorageSync
原理:從 key 讀取內容,若不存在返回 undefined 或空值。
異步版本:uni.getStorage(OBJECT)
參數表:
|
參數名
|
類型
|
必填
|
説明
|
|
key
|
String
|
是
|
緩存鍵名
|
|
success
|
Function
|
是
|
回調,res = { data: 讀取內容 }
|
|
fail
|
Function
|
否
|
失敗回調
|
|
complete
|
Function
|
否
|
結束回調
|
success 返回值:{ data: Any }
示例:
asyncGetData() {
uni.getStorage({
key: 'user_info',
success: (res) => {
if (res.data) {
console.log('獲取數據:', res.data.name);
this.userName = res.data.name; // 更新頁面數據
} else {
console.log('緩存為空');
}
},
fail: (err) => {
console.error('獲取失敗:', err);
}
});
}
解釋:讀取後直接綁定到頁面 data,實現響應式更新。在組件 mounted 鈎子中調用,能快速初始化視圖。
同步版本:uni.getStorageSync(key)
參數:key (String,必填)。
返回值:Any(不存在時 undefined)。
示例:
try {
const userInfo = uni.getStorageSync('user_info');
if (userInfo) {
console.log('同步獲取:', userInfo.name);
} else {
console.log('無數據');
}
} catch (e) {
console.error('同步獲取失敗:', e);
}
規則:
- 默認值處理:讀取前可檢查 typeof res.data !== ‘undefined’。
- 性能提示:高頻讀取用同步,低頻用異步。同步版本在初始化階段特別高效,能節省幾毫秒加載時間。
2.3 移除數據:uni.removeStorage / uni.removeStorageSync
原理:刪除指定 key,若不存在仍返回成功。
異步版本:uni.removeStorage(OBJECT)
參數表:
|
參數名
|
類型
|
必填
|
説明
|
|
key
|
String
|
是
|
要移除的鍵名
|
|
success
|
Function
|
是
|
成功回調,無參數
|
|
fail
|
Function
|
否
|
失敗回調
|
|
complete
|
Function
|
否
|
結束回調
|
示例:
removeData() {
uni.removeStorage({
key: 'user_info',
success: () => {
console.log('移除成功');
uni.showToast({ title: '緩存已清除' });
}
});
}
同步版本:uni.removeStorageSync(key)
示例:
try {
uni.removeStorageSync('user_info');
console.log('同步移除成功');
} catch (e) {
console.error('移除失敗:', e);
}
注意事項:移除後,相關頁面需刷新數據源,避免顯示舊值。結合事件總線,能通知其他組件更新。
2.4 清空數據:uni.clearStorage / uni.clearStorageSync
原理:移除所有緩存鍵值對,慎用!
異步版本:uni.clearStorage(OBJECT)
參數:success/fail/complete(可選)。
示例:
clearAll() {
uni.clearStorage({
success: () => {
console.log('全部清空成功');
// 跳轉登錄頁
uni.reLaunch({ url: '/pages/login/login' });
}
});
}
同步版本:uni.clearStorageSync()
示例:
try {
uni.clearStorageSync();
console.log('同步清空成功');
} catch (e) {
console.error('清空失敗:', e);
}
規則:
- 備份重要數據:清空前用 getStorageInfo 導出 keys。
- 平台影響:非 App 端可能重置 deviceId。在生產環境中,我會添加確認對話框,防止誤操作。
2.5 獲取存儲信息:uni.getStorageInfo / uni.getStorageInfoSync
原理:查詢當前緩存狀態,用於監控和調試。
異步版本:uni.getStorageInfo(OBJECT)
success 返回值:
|
參數名
|
類型
|
説明
|
|
keys
|
Array
|
所有鍵名數組
|
|
currentSize
|
Number
|
當前佔用 KB
|
|
limitSize
|
Number
|
限制 KB
|
示例:
getInfo() {
uni.getStorageInfo({
success: (res) => {
console.log('鍵列表:', res.keys);
console.log('佔用:', res.currentSize + 'KB / ' + res.limitSize + 'KB');
}
});
}
同步版本:uni.getStorageInfoSync()
示例:
try {
const res = uni.getStorageInfoSync();
console.table(res); // 表格輸出
} catch (e) {
console.error(e);
}
應用:在設置頁顯示存儲使用率,提示用户清理。定期調用能幫助診斷內存問題。
通過這些基礎 API,開發者可快速實現簡單緩存。接下來,我們探討如何在複雜場景中擴展它們。
三、高級用法與技巧
基礎 API 雖強大,但實際項目中需處理過期、集成和安全等問題。本節提供一些實用技巧,幫助你構建更robust的緩存系統。
3.1 緩存過期機制實現
原理:UniApp 無內置過期,需手動添加時間戳判斷。
實現步驟:
- 存儲時附加 timestamp: Date.now()。
- 讀取時計算差值,超閾值則移除並返回 null。
示例(工具函數):
// utils/cache.js
const CACHE_EXPIRE = 60 * 60 * 1000; // 1小時
export function setWithExpire(key, data, expire = CACHE_EXPIRE) {
const cacheObj = {
data,
timestamp: Date.now() + expire
};
try {
uni.setStorageSync(key, JSON.stringify(cacheObj));
} catch (e) {
console.error('設置過期緩存失敗:', e);
}
}
export function getWithExpire(key) {
try {
const str = uni.getStorageSync(key);
if (!str) return null;
const cacheObj = JSON.parse(str);
if (Date.now() > cacheObj.timestamp) {
uni.removeStorageSync(key); // 過期移除
return null;
}
return cacheObj.data;
} catch (e) {
console.error('獲取過期緩存失敗:', e);
return null;
}
}
使用:
// 存儲
setWithExpire('article_list', articles, 30 * 60 * 1000); // 30分鐘
// 讀取
const articles = getWithExpire('article_list');
if (articles) {
this.list = articles;
} else {
// 從服務器重新獲取
}
優勢:防止陳舊數據,提升數據新鮮度。在電商 App 中,我用它緩存商品價格,過期後自動刷新,避免用户看到過時信息。
3.2 與 Vuex/Pinia 集成持久化
原理:Vuex 內存狀態非持久,結合緩存實現重啓恢復。
Vuex 示例(store/index.js):
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
user: null,
cart: []
},
mutations: {
SET_USER(state, user) {
state.user = user;
// 持久化
uni.setStorageSync('vuex_user', JSON.stringify(user));
},
SET_CART(state, cart) {
state.cart = cart;
uni.setStorageSync('vuex_cart', JSON.stringify(cart));
}
},
actions: {
initFromCache({ commit }) {
// 應用啓動時恢復
const userStr = uni.getStorageSync('vuex_user');
if (userStr) commit('SET_USER', JSON.parse(userStr));
const cartStr = uni.getStorageSync('vuex_cart');
if (cartStr) commit('SET_CART', JSON.parse(cartStr));
}
}
});
export default store;
main.js 中調用:
import store from './store';
Vue.prototype.$store = store;
store.dispatch('initFromCache'); // App 啓動時執行
Pinia 變體:類似,使用 defineStore 的 persist 插件(社區擴展)。
規則:僅持久關鍵狀態,避免緩存大對象。在大型項目中,這種集成能讓狀態管理更可靠,用户重啓 App 後無縫繼續。
3.3 全局緩存管理工具封裝
原理:統一入口,簡化多處調用,支持命名空間。
示例(utils/storageManager.js):
class StorageManager {
constructor(namespace = '') {
this.namespace = namespace ? `${namespace}_` : '';
}
set(key, data) {
try {
uni.setStorageSync(this.namespace + key, data);
} catch (e) {
throw new Error(`存儲失敗: ${e.message}`);
}
}
get(key, defaultValue = null) {
try {
return uni.getStorageSync(this.namespace + key) || defaultValue;
} catch (e) {
console.warn(`獲取失敗: ${key}`);
return defaultValue;
}
}
remove(key) {
try {
uni.removeStorageSync(this.namespace + key);
} catch (e) {}
}
clear() {
try {
uni.clearStorageSync();
} catch (e) {}
}
getInfo() {
try {
return uni.getStorageInfoSync();
} catch (e) {
return null;
}
}
}
// 使用
const userStorage = new StorageManager('user');
userStorage.set('token', 'xyz');
const token = userStorage.get('token');
優勢:避免 key 衝突,支持模塊化(如 ‘user_token’)。在團隊開發中,這樣的封裝能減少代碼重複,提高維護性。
3.4 數據加密存儲
原理:敏感數據(如 Token)易被逆向,需 AES 加密。
依賴:UniApp 無內置 crypto,App 端用 plus.crypto(需條件編譯)。
示例(簡單 Base64 + 自定義密鑰,H5/小程序通用):
// utils/encrypt.js
const KEY = 'MySecretKey12345'; // 生產環境用隨機密鑰
function encrypt(data) {
const str = typeof data === 'object' ? JSON.stringify(data) : data;
let result = '';
for (let i = 0; i < str.length; i++) {
result += String.fromCharCode(str.charCodeAt(i) ^ KEY.charCodeAt(i % KEY.length));
}
return btoa(result); // Base64 編碼
}
function decrypt(encrypted) {
try {
const decoded = atob(encrypted);
let result = '';
for (let i = 0; i < decoded.length; i++) {
result += String.fromCharCode(decoded.charCodeAt(i) ^ KEY.charCodeAt(i % KEY.length));
}
return JSON.parse(result); // 假設對象
} catch (e) {
return null;
}
}
// 使用
uni.setStorageSync('encrypted_token', encrypt('abc123'));
const token = decrypt(uni.getStorageSync('encrypted_token'));
注意:H5 用 CryptoJS 庫(npm 引入),App 用原生。對於金融類 App,這層保護至關重要,能防範簡單逆向工程。
3.5 批量操作與事務模擬
原理:無原生事務,用 Promise.all 模擬批量。
示例:
async batchSet(items) {
const promises = items.map(({ key, data }) =>
new Promise((resolve, reject) => {
uni.setStorage({
key,
data,
success: resolve,
fail: reject
});
})
);
try {
await Promise.all(promises);
console.log('批量存儲成功');
} catch (e) {
console.error('批量失敗,回滾');
// 模擬回滾:清空相關鍵
items.forEach(({ key }) => uni.removeStorageSync(key));
}
}
// 調用
this.batchSet([
{ key: 'config1', data: { theme: 'dark' } },
{ key: 'config2', data: { lang: 'zh' } }
]);
規則:失敗時回滾,確保一致性。適用於配置批量更新,在初始化多模塊時很實用。
四、實際應用場景
本節通過 4 個典型場景,展示緩存的實戰價值。每場景包含需求、實現和優化。
4.1 用户登錄狀態管理
需求:登錄後保存 Token 和用户信息,退出時清除;重啓 App 自動驗證。
實現:
- 登錄頁(login.vue):
login() {
// 模擬 API
const user = { id: 1, name: '李四', token: 'def456' };
uni.setStorageSync('user_token', user.token);
uni.setStorageSync('user_info', JSON.stringify(user));
uni.switchTab({ url: '/pages/home/home' });
}
- Home 頁(home.vue):
onLoad() {
const token = uni.getStorageSync('user_token');
if (token) {
const userStr = uni.getStorageSync('user_info');
this.user = userStr ? JSON.parse(userStr) : null;
} else {
uni.reLaunch({ url: '/pages/login/login' });
}
},
methods: {
logout() {
uni.removeStorageSync('user_token');
uni.removeStorageSync('user_info');
uni.reLaunch({ url: '/pages/login/login' });
}
}
優化:集成過期(3.1),每 7 天重登。
在實際項目中,可添加 JWT 解析驗證 Token 有效性:
// 驗證 Token
function isTokenValid(token) {
try {
const payload = JSON.parse(atob(token.split('.')[1]));
return Date.now() < payload.exp * 1000;
} catch (e) {
return false;
}
}
這確保安全,防止過期 Token 誤用。在社交 App 中,這種機制讓用户體驗更流暢。
4.2 配置信息持久化
需求:保存主題色、語言等設置,重啓生效。
實現:
- 設置頁(setting.vue):
changeTheme(color) {
uni.setStorageSync('app_theme', color);
// 動態更新全局樣式(需 CSS 變量)
const dom = document.documentElement;
dom.style.setProperty('--theme-color', color);
}
onLoad() {
const savedTheme = uni.getStorageSync('app_theme') || '#007AFF';
// 應用主題
}
優化:用 getStorageInfo 監控,超 1MB 提示清理。結合 Vuex(3.2),實現響應式切換。
擴展:多語言支持:
// 存儲語言包
uni.setStorageSync('lang_pack', { zh: { hello: '你好' }, en: { hello: 'Hello' } });
const lang = uni.getStorageSync('current_lang') || 'zh';
this.messages = uni.getStorageSync('lang_pack')[lang];
這在國際化 App 中實用,減少 bundle 大小。用户切換語言時,立即生效,無需重啓。
4.3 離線數據緩存
需求:緩存 API 返回的文章列表,支持無網瀏覽。
實現(使用 3.1 過期):
// 獲取列表
async fetchArticles() {
const cached = getWithExpire('articles');
if (cached) {
this.articles = cached;
return;
}
try {
const res = await uni.request({ url: '/api/articles' });
setWithExpire('articles', res.data, 24 * 60 * 60 * 1000); // 24小時
this.articles = res.data;
} catch (e) {
console.error('網絡錯誤,使用緩存');
this.articles = cached || [];
}
}
優化:分頁緩存,如 ‘articles_page_1’。添加網絡狀態檢測:
uni.getNetworkType({
success: (res) => {
if (res.networkType === 'none') {
// 僅用緩存
}
}
});
這提升了魯棒性,在弱網環境閃光。新聞類 App 中,用户地鐵上也能閲讀緩存內容。
4.4 列表分頁緩存
需求:電商商品列表,分頁加載,緩存每頁數據。
實現:
loadPage(page = 1) {
const key = `goods_page_${page}`;
const cached = uni.getStorageSync(key);
if (cached) {
this.goods = [...this.goods, ...cached];
return;
}
uni.request({
url: `/api/goods?page=${page}`,
success: (res) => {
uni.setStorageSync(key, res.data);
this.goods = [...this.goods, ...res.data];
}
});
}
優化:預加載下一頁,移除舊頁(如 >10 頁清空)。結合 getStorageInfo,避免總大小超限。
擴展討論:在高併發場景,可用 IndexedDB(H5 專用,條件編譯)補充大列表緩存:
<script>
import { openDB } from 'idb'; // npm idb
const db = await openDB('goods_db', 1, {
upgrade(db) {
db.createObjectStore('pages');
}
});
await db.put('pages', data, `page_${page}`);
</script>
這在 Web 端處理海量數據時高效,結合緩存層,能實現混合存儲策略。
五、性能優化與最佳實踐
5.1 同步 vs 異步選擇
- 異步優先:95% 場景用回調/Promise,避免 UI 阻塞。示例:onLoad 中異步 get。
- 同步場景:啓動時快速恢復,或簡單工具函數。
- 最佳實踐:封裝 Promise 化異步:
function setStoragePromise(key, data) {
return new Promise((resolve, reject) => {
uni.setStorage({
key, data,
success: resolve,
fail: reject
});
});
}
// 使用 await setStoragePromise('key', data);
在我的項目中,統一用 Promise,能讓 async/await 代碼更優雅。
5.2 存儲大小管理
- 監控:定期調用 getStorageInfo,若 currentSize > 80% limitSize,清理舊數據。
- 壓縮:大對象用 lz-string 庫壓縮(npm 引入)。
- 實踐:設置頁添加“清理緩存”按鈕:
clearOld() {
const res = uni.getStorageInfoSync();
if (res.currentSize > res.limitSize * 0.8) {
// 移除 7 天前數據(結合 3.1)
res.keys.forEach(key => {
if (getWithExpire(key) === null) uni.removeStorageSync(key);
});
}
}
定期清理能保持 App 輕量,尤其在低端設備上。
5.3 錯誤處理與調試
- 統一日誌:用 console.error + uni.reportEvent 上報。
- 調試工具:HBuilderX 控制枱查看 Storage,Chrome DevTools 檢查 H5 localStorage。
- 實踐:添加 try-catch 包裝所有操作,fail 回調 toast 提示。遇到序列化錯誤時,fallback 到字符串存儲。
5.4 跨平台兼容
- 條件編譯:#ifdef APP 用 plus.storage 擴展。
- 測試:多端運行,關注小程序審核(如支付寶 10MB 限)。
- 實踐:manifest.json 中配置 storage 權限。在 CI/CD 中集成多端測試腳本。
5.5 清理策略
- 自動:應用退出時 clear(可選)。
- 手動:用户設置頁一鍵清。
- 智能:基於使用頻率,LRU(最近最少用)算法移除(自定義 Map 實現)。
示例 LRU:
class LRUCache {
constructor(maxSize) {
this.maxSize = maxSize;
this.cache = new Map();
}
set(key, value) {
if (this.cache.has(key)) this.cache.delete(key);
this.cache.set(key, value);
if (this.cache.size > this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}
get(key) {
if (this.cache.has(key)) {
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
return null;
}
}
用它包裝 Storage,能智能管理熱數據。
六、常見問題與解決方案
6.1 常見錯誤
- 序列化失敗:data 含不可序列化類型。
解:預檢查JSON.stringify(data)不拋錯。 - Key 衝突:用系統前綴。
解:命名規範,如 ‘app_user_token’。 - 讀取 undefined:key 不存在。
解:默認值|| {}。
6.2 平台特定問題
- H5 緩存丟失:瀏覽器隱私模式。
解:fallback 到 sessionStorage。 - 小程序超限:微信 10MB。
解:分 key 存儲,定期 getStorageInfo 檢查。 - App 無限制濫用:佔用設備空間。
解:設置軟上限 50MB,自行清理。
6.3 調試技巧
- 打印 keys:循環 getStorageSync(key) 查看內容。
- 模擬清理:clearStorageSync() + 重載。
- 工具:UniApp 插件“Storage Viewer”。在開發時,添加一個調試模式,暴露所有 keys 到控制枱。
七、擴展與進階
7.1 與其他存儲結合
- SQLite(App 端):複雜數據用 uni.requireNativePlugin(‘sqlite’)。
示例:用户訂單表,緩存僅存 ID 列表。 - IndexedDB(H5):大文件緩存。
實踐:圖片縮略圖存 IndexedDB,詳情存 Storage。混合使用能平衡性能和容量。
7.2 雲端同步
- 原理:本地變更時上傳雲(uniCloud),拉取時合併。
- 示例:登錄後 syncCacheToCloud(),用 diff 算法避免覆蓋。
async syncCache() {
const localKeys = uni.getStorageInfoSync().keys;
const cloudData = await uniCloud.callFunction({ name: 'getCache' });
localKeys.forEach(key => {
if (!cloudData.has(key)) {
uniCloud.callFunction({ name: 'uploadCache', data: { key, value: uni.getStorageSync(key) } });
}
});
}
這在多設備同步場景中強大,如筆記 App。
7.3 自定義緩存模塊
- 基於 Redux-like:狀態 + reducer + storage middleware。
- 進階:支持 RxJS 響應式緩存更新。示例:訂閲緩存變化,自動 UI 刷新。
// 用 RxJS
import { fromEvent } from 'rxjs';
const storageEvent = fromEvent(window, 'storage');
storageEvent.subscribe(event => {
if (event.key === 'my_key') {
// 更新狀態
}
});
這讓緩存成為響應式數據源。