ReactNative實現鍵值對的同步存取
官方 AsyncStorage
- AsyncStorage 是一個簡單的、異步的、持久化的 Key-Value 存儲系統。
- 由於是異步的,每個方法都需要返回一個 Promise,不滿足同步存取需求。
- 它的使用請參考官方實例。
實現同步存取的兩種方案
使用靜態對象持有
思路分析:
- 在App啓動時,從 AsyncStorage 中異步讀取所有鍵值對,並賦值給靜態變量;
- 調用 setValue(key) 時先將其加入到靜態變量中,之後再異步存入 AsyncStorage;
- 調用 getValue(key) 時直接從靜態變量中讀取,實現同步存取;
優缺點分析:
- 優點:代碼實現量少,不需要引入其他第三方庫做支撐,存儲任務實際上仍舊由系統提供的 AsyncStorage 完成。
- 缺點:由於第一步的 init 讀取所有鍵值對仍然是異步操作,所以需要在 App 初始化時完成這一操作,並且在初始化時不能執行同步讀取,因爲此時可能靜態變量可能並未賦值成功。
代碼實現:
export default class SyncStorage { static cache: { [key: string]: string } = {} // 初始化需要在App啓動時執行 static async init() { let keys = await AsyncStorage.getAllKeys() let items = await AsyncStorage.multiGet(keys).then() items.map(([key, value]) => { this.cache[key] = value }) } static getValue(key: string) { return this.cache[key] } static setValue(key: string, value: string) { if (this.cache[key] === value) return this.cache[key] = value AsyncStorage.setItem(key, value) } static removeKey(key: string) { delete this.cache[key] AsyncStorage.removeItem(key) } }
使用realm.js自行封裝
思路分析:
- 由於我們經常有一些需求是在 App 初始化時就要進行 Key-Value 的讀取,從而選擇UI上的展示內容,所以上面的靜態變量持有的方案,並不能滿足這種需求。
- 通過閱讀 react-native AsyncStorage 部分的Android實現源碼可以發現,facebook 使用了 SQLiteDatabase 來實現 Key-Value 的存取,那麼我們也可以自己使用數據庫實現一套簡單的鍵值對存取方案。
- 由於 realm 提供了 ReactNative 版本,集成更加簡單高效,所以這裏使用 realm 來完成這套方案。
代碼實現:
使用 realm 實現存取操作
/** * 定義Key-Value類 */ class Config { private _key: string private _value: string constructor(key: string, value: string) { this._key = key this._value = value } get key(): string { return this._key } get value(): string { return this._value } } /** * 定義Realm-Schema */ const ConfigSchema = { name: Config.name, primaryKey: 'key', properties: { key: 'string', value: 'string' } } // 獲取 realm 存取對象 const realm = new Realm({schema: [ConfigSchema, MediaSchema]}) /** * 使用 realm 實現 Key-Value 存取 */ class DBManager { static insertConfig(config: Config) { realm.write(() => { realm.create(Config.name, config) }) } static updateConfig(config: Config) { realm.write(() => { realm.create(Config.name, config, true) }) } static queryConfig(key: string): Config { return realm.objectForPrimaryKey<Config>(Config.name, key)! } } /** * 封裝存取 Util,供外界調用 */ export default class SyncStorage { static putValue(key: string, value: string) { if (DBManager.queryConfig(key) == undefined) DBManager.insertConfig(new Config(key, value)) else DBManager.updateConfig(new Config(key, value)) } static getValue(key: string): string | undefined { let config: Config = DBManager.queryConfig(key) return config == undefined ? undefined : config.value } }