Лесен начин за синхронизиране с locaStorage и запазване на js типове?

Имам приложение, което записва данни и чете данни от localStorage.

По принцип имам масив от обекти, които променям и чета много пъти в кода, и всички тези промени искам да поддържам в синхрон с localStorage.

Сега мога да създам функция, която да я синхронизира всеки път, когато имам нужда от нея в кода, но просто ми звучи малко грозно и неоптимизирано. Като този

arrayOfObjects.push(newItem);
localStorage.setItem('objects', arrayOfObjects);

и тогава

arrayOfObjects = localStorage.getItem('objects');
length = arrayOfObjects.length

Това би било наистина лошо, защото трябва да го чета и пиша стотици пъти в кода, ужасно решение.

Сега мога също да го капсулирам във функция, така че всички записи, четения и синхронизации да преминават през него, но все пак ще му липсват много функционалности, защото все още ще трябва да се справям с arrayOfObjects като тип масив за множество операции с масиви като .push и .дължина.

Някакви идеи как мога да накарам този масив да се синхронизира с localStorage с възможно най-малко редове код? Има ли някакъв начин да мога просто да пиша/чета в тип масив директно в localStorage?


person sigmawf    schedule 11.04.2018    source източник
comment
but it just sounds a bit ugly and unoptimized to me сигурни ли сте, че това не е преждевременна оптимизация? Аз лично бих казал, че направете sync функция, която върши работата и вижте дали ще се отрази на производителността. Ако го направи, тогава можете да го оптимизирате, но след като интерфейсът е там, всичко, от което се нуждаете, е да промените sync и нищо друго. Можете например да debounce на функцията и това може да е всичко, от което се нуждаете. Или може би нещо различно. Трудно е да се каже, без да се знае конкретният профил на ефективност на вашия случай на употреба.   -  person VLAZ    schedule 11.04.2018
comment
Съжалявам, че нямах предвид оптимизиран по отношение на производителността, а като цялостна четливост на кода и поддръжка.   -  person sigmawf    schedule 11.04.2018
comment
В такъв случай бихте могли да направите същото - да направите всички промени в масива чрез извикване на функция, така че никога да не взаимодействате директно с масива - това означава, че можете да добавите каквато искате логика там, включително запазване на масива към locareage. Като алтернатива можете да настроите масива да бъде наблюдаем и да прикачите наблюдател, който се синхронизира с локално хранилище при всяка промяна.   -  person VLAZ    schedule 11.04.2018


Отговори (1)


Можете да създадете свой собствен Class, който разширява родния Array, като единствената разлика е, че го запазва в LocalStorage, когато се извърши операция.

Когато искате да възстановите този специален Array, просто ще извикате неговия .restore() метод, който основно го възстановява обратно от LocalStorage.

Ето един пример:

class LocalArray extends Array {
  constructor(name, ...items) {
    super(...items)
    this._name = name
  }

  push(item) {
    Array.prototype.push.call(this, item)

    this._save()
  }

  pop() {
    const popped = Array.prototype.pop.call(this)

    this._save()

    return popped
  }

  // rest of operations, i.e splice, reduce, etc..

  restore() {
    const data = window.localStorage.getItem(this._name)
    const items = data ? JSON.parse(data) : []

    items.forEach(item => {
      Array.prototype.push.call(this, item)
    })
  }

  _save() {
    window.localStorage.setItem(this._name, JSON.stringify(this))
  }
}

И ето как се използва:

const users = new LocalArray('users')
users.push({ name: 'John Doe' })
users.push({ name: 'Mary Jane' })
users.pop()

Както можете да си представите, LocalStorage сега ще съдържа елемент 'users': [{"name":"John Doe"}].

.. и за възстановяване:

const users = new LocalArray('users')
users.restore()

console.log(users) // logs [{ name: 'John Doe' }]

Имайте предвид, че тук има значителни последици за производителността. Всеки път, когато .push() например, ще задействате _save() на непрекъснато нарастващ масив.

Можете да подобрите това, като запазите делта (промени) във вашия масив в LocalStorage, вместо целия обект, но в този момент нещата започват да се усложняват.

Използвайте разумно.

person nicholaswmin    schedule 11.04.2018
comment
Това може да е един от случаите, в които Proxy би било по-подходящо. Подкласирането тук наистина няма смисъл. - person Bergi; 12.04.2018
comment
@Bergi Наистина няма смисъл е доста силно и неуместно твърдение. Прокситата може да са друга алтернатива, но това все още е жизнеспособно решение. Въпреки че това е ваш прерогатив, бих предпочел да напишете отговори, описващи вашите алтернативни решения, вместо да оставяте полуобмислени коментари за отговори, които не намирате за перфектни. - person nicholaswmin; 12.04.2018
comment
Харесвам вашето решение, но също така ми е интересно да науча как да го направя с помощта на прокси, идеи? - person sigmawf; 12.04.2018
comment
Ако някой търси решение, използващо прокси в бъдеще: stackoverflow.com/questions/35610242/ - person sigmawf; 12.04.2018
comment
@NicholasKyriakides Подкласирането не е жизнеспособно, ако искате да откриете неща като const users = new LocalArray('users'); users[0] = {name: 'John Doe'}; users[1] = {name: 'Mary Jane'}; и много други. - person Bergi; 12.04.2018
comment
@Bergi Тогава следващия път напишете това като предупреждение в коментарите си и бъдете малко по-конструктивни. OP спомена push в своя код и моят отговор го адресира. Също така можете да използвате нещо като метод .set(index, element), за да направите това, което споменахте, но това е извън моята гледна точка. - person nicholaswmin; 12.04.2018
comment
@NicholasKyriakides Съжалявам, мислех, че споменаването на проксита ще бъде достатъчно конструктивно и разликата ще бъде очевидна. Изглежда поне е довело OP до добър ресурс, това е всичко, към което се стремях :-) - person Bergi; 12.04.2018
comment
@Bergi Бъдете по-внимателни с коментарите си следващия път. Те възпират ОП да види каквато и да е стойност на решението, което предлагам, и ме възпират да напиша каквито и да е отговори, ако те ще бъдат проверени до съвършенство. Ние сме тук, за да помогнем и да дадем различни мнения. Имам предвид вашия doesn't make sense коментар, който повече или по-малко намеква, че това е безсмислен отговор, което не е така. Това е всичко. Посочването на Proxies със сигурност беше конструктивно IMO. - person nicholaswmin; 12.04.2018
comment
@NicholasKyriakides Добре, съжалявам за езика, който може да е бил неподходящ. Все още получавате гласа си „за“ и приемате, така че няма нищо лошо :-) - person Bergi; 12.04.2018
comment
@Bergi За щастие почти не ме е грижа за гласовете. Извинението е прието. - person nicholaswmin; 12.04.2018