Простой способ синхронизации с 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 и ничего больше. Вы можете, например, отклонить функцию, и это может быть все, что вам нужно. Или, возможно, что-то другое. Трудно сказать, не зная конкретного профиля производительности вашего варианта использования.   -  person VLAZ    schedule 11.04.2018
comment
Извините, я имел в виду оптимизацию не с точки зрения производительности, а с точки зрения общей читабельности и обслуживания кода.   -  person sigmawf    schedule 11.04.2018
comment
В этом случае вы могли бы сделать то же самое - внести все изменения в массив с помощью вызова функции, поэтому вы никогда не взаимодействуете с массивом напрямую - это означает, что вы можете добавить туда любую логику, которую вы хотите, включая сохранение массива в хранилище. Кроме того, вы можете настроить массив как наблюдаемый и подключить наблюдатель, который синхронизируется с локальным хранилищем при любых изменениях.   -  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 Тогда в следующий раз напиши это как предостережение в своих комментариях и будь немного более конструктивным. ОП упомянул push в своем коде, и мой ответ касается этого. Также вы можете использовать что-то вроде метода .set(index, element), чтобы делать то, что вы упоминаете, но это не относится к моей точке зрения. - person nicholaswmin; 12.04.2018
comment
@NicholasKyriakides Извините, я думал, что упоминание прокси было бы достаточно конструктивным, и разница была бы очевидной. Кажется, это привело ОП к хорошему ресурсу, по крайней мере, это все, к чему я стремился :-) - person Bergi; 12.04.2018
comment
@Bergi В следующий раз будьте более внимательны к своим комментариям. Они удерживают ОП от того, чтобы увидеть какую-либо ценность решения, которое я предлагаю, и они удерживают меня от написания каких-либо ответов, если они будут тщательно изучены до совершенства. Мы здесь, чтобы помочь и высказать разные мнения. Я имею в виду ваш комментарий doesn't make sense, который более или менее намекает на то, что это бессмысленный ответ, а это не так. Это все. Указание на Proxies было, безусловно, конструктивным ИМО. - person nicholaswmin; 12.04.2018
comment
@NicholasKyriakides Хорошо, извините за язык, он мог быть неуместным. Вы все еще получили свой голос и согласились, так что не причините вреда :-) - person Bergi; 12.04.2018
comment
@Bergi К счастью, меня почти не волнуют голоса. Извинения приняты. - person nicholaswmin; 12.04.2018