Веб-хранилище: как редактировать элементы объекта

В TypeScript у меня есть класс-оболочка вокруг API веб-хранилища. Чтобы упростить использование хранилища, я инициализировал свойство класса для каждого элемента, который необходимо сохранить в приложении. Ниже приведен класс my wrapper (написан в TypeScript)

экспорт класса StorageService

get Storage(){return localStorage}
get testData(){return this.getItem('testData')}
set testData(val){this.setItem('testData',val)}

getItem(key:string){return JSON.parse(this.Storage.getItem(key))}
setItem(key:string, data:any){this.Storage.setItem(key, JSON.stringify(data))}
removeItem(key){this.Storage.removeItem(key)}
clear(){this.Storage.clear()}

в другом месте приложения я хочу взаимодействовать с объектом testDataи его свойствами-членами. Следующие работы отлично:

storage.testData = {name:'Mary',age:6};
console.log(storage.testData); //initial object is retrieved

Однако, если я пытаюсь изменить свойство testData, а не установить весь объект, setItemметод никогда не вызывается и содержимое хранилища не изменяется.

storage.testData.age = 10;
console.log(storage.testData); //{name:'Mary',age:6} <- age was not changed

Интуитивное исправление состоит в том, чтобы сначала получить сохраненный объект, затем обновить его и, наконец, сохранить обновленное значение

var temp = storage.testData;
temp.age = 10;
storage.testData = temp;
console.log(storage.testData); //{name:'Mary',age:10} <- age is updated

Это хорошо на небольшом объекте, но это не масштабируется хорошо. Представьте, что testData имеет 50 или 60 свойств, и что в нескольких точках приложения мне нужно изменить только 1 или 2 из них. Нет смысла устанавливать каждое свойство каждый раз. В любом случае, я не могу изменить остальную часть приложения; я только предоставляю интерфейс хранения.

Мой вопрос: как я могу предоставить метод хранения, который позволяет устанавливать/изменять свойства объектов в хранилище напрямую, а не предоставлять полный объект для хранения каждый раз? В идеале потребляющий код просто вызовет store.testData.age = valueизменение текущего сохраненного значения.

PS: также это может быть для другой темы, но если доступ к localStorage много будет действительно замедлить приложение (в соответствии с 1-м комментарием ниже), может быть, я не использую веб-хранилище, как это предназначено? Возможно, моя оболочка могла бы хранить значения в памяти, но отправлять их все в хранилище с заданными интервалами; скажем, каждые 3 минуты? Я использовал, чтобы строго в памяти объекты отражают состояние приложения, но все теряется, когда пользователь переходит или обновляет страницу

1 ответ

  1. Как я уже упоминал в OP, я, возможно, не смогу внести изменения в интерфейс. В идеале вызывающий код может вносить изменения в свойства элементов объектов в хранилище. Я думаю, что попробую гибридный подход. Храните элементы в памяти, но каждый установленный интервал (или по определенной команде) фиксирует их в хранилище. Ниже приведен мой упрощенный StorageService в TypeScript

    //push items to storage regularly
    constructor() {this.restore();this.intervalID = setInterval(()=>this.commit(),this.COMMIT_INTERVAL*1000)}
    
    Storage = window.localStorage;
    COMMIT_INTERVAL = 60;//interval, in seconds, upon which changes are saved to storage
    private intervalID:number;
    private keys = ['testData', 'testData2']; //key names used set items in storage
    
    //when data is accessed, return it from memory. If not there (eg after a page refresh), then from storage
    private _testData = null;
    public get testData(){return this._testData || this.getItem(this.keys[0])}
    public set testData(val){this._testData = val} //we store in memory; not directly in storage until commit() is called.
    
    //remove each value from memore and clear web storage
    public clear(){
        this.keys.forEach(key=>this['_'+key]=null,this);
        this.Storage.clear()
    }
    
    // store memory data in web storage
    public commit(){    
        this.keys.forEach(key => this.setItem(key,this['_'+key]),this);
    }
    
    //restore items from web storage. This is done in the constructor
    private restore(){
        this.keys.forEach(key => this[key] = this.getItem(key) || this[key])
    }
    
    //the methods that actually connect to storage are all private. Calling code must use commit() to interact with storage
    private getItem(key:string){
        return JSON.parse(this.Storage.getItem(key));
    }
    private removeItem(key){
        this.Storage.removeItem(key);
    }
    private setItem(key:string, data:any){
        this.Storage.setItem(key, JSON.stringify(data));
    }
    

    Эта служба позволяет API, который использует вызывающий код, оставаться неизменным: testData.age = 10будет обновлять объект в памяти, и в конечном итоге (когда commit()вызывается) в хранилище.

    Пожалуйста, дайте мне обратную связь. Я новичок в кодировании и устал от дорогостоящих ошибок.