Почему я должен использовать immutablejs над объектом.замерзнуть?

Я исследовал в сети о преимуществах immutablejs над Object.freeze() но не нашел ничего удовлетворительного!

мой вопрос: почему я должен использовать эту библиотеку и работать с неродными структурами данных, когда я могу заморозить простой старый объект javascript?

6 ответов


Я не думаю, что вы поняли, что immutablejs предлагает. Это не библиотека, которая просто делает ваши объекты неизменяемыми, это библиотека, работающая с неизменяемыми значениями.

не просто повторяя их docs и миссия, я скажу две вещи, которые он предоставляет:

  1. типы. Они реализовали (неизменяемые) бесконечные диапазоны, стеки, упорядоченные множества, списки ...

  2. все их типы реализованы как Постоянные Структуры Данных.

я наврал, вот цитата из их заявления о миссии:

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

Я призываю вас прочитать статьи и видео, на которые они ссылаются, и больше о постоянных структурах данных (поскольку они the thing immutablejs is about), но я резюмирую в предложении или около того:

давайте представим, что вы пишете игру и у вас есть игрок, который сидит на 2D плоскости. Вот, например, Боб:--7-->

var player = {
  name: 'Bob',
  favouriteColor: 'moldy mustard',

  x: 4,
  y: 10
};

поскольку вы выпили FP koolaid, вы хотите заморозить игрока (brrr! надеюсь, Боб получил свитер):

var player = Object.freeze({
    name: 'Bob',
    ...
});

и теперь введите свой игровой цикл. На каждом ТИКе позиция игрока меняется. Мы не можем просто обновить объект player, так как он заморожен, поэтому мы копируем его:

function movePlayer(player, newX, newY) {
    return Object.freeze(Object.assign({}, player, { x: newX, y: newY }));
}

это прекрасно и денди, но обратите внимание, сколько бесполезного копирования мы делаем: на каждом ТИКе мы создаем новый объект, перебираем один из наших объектов, а затем назначаем некоторые новые значения поверх них. На каждом ТИКе, на каждом из ваших объектов. Это довольно глоток.

Immutable оборачивает это для вас:

var player = Immutable.Map({
    name: 'Bob',
    ...
});

function movePlayer(player, newX, newY) {
    return player.set('x', newX).set('y', newY);
}

и через Magic * Magic Magic Persistent*ヽ постоянных структур данных они обещают сделатьменьше количество возможных операций.

существует также разница в мышлении. При работе с "простым старым [замороженным] объектом javascript" действия по умолчанию со стороны все принять изменчивость, и вы должны работать дополнительную милю для достижения значимого неизменность (то есть неизменность, которая признает, что состояние существует). Это часть причины freeze существует: когда вы пытаетесь сделать иначе, вещи паники. С Immutablejs неизменяемость, конечно, предположение по умолчанию, и он имеет хороший API поверх него.

это не значит, что все розовое и розовое с вишней сверху. Конечно, у всего есть свои недостатки, и вы не должны всюду втискивать неизменное только потому, что можете. Иногда, просто freezeing объект хорошо Достаточно. Черт возьми, большую часть времени это больше чем достаточно. Это полезная библиотека, которая имеет свою нишу, просто не увлекайтесь шумихой.


по моим критерии, неизменный.js is оптимизированные для операций записи быстрее, чем объект.assign (), однако, медленнее для операций чтения. Таким образом, описание зависит от типа вашего приложения и его отношения чтения/записи. Ниже приводится резюме результатов контрольных показателей:

-- Mutable
Total elapsed = 103 ms = 50 ms (read) + 53 ms (write).

-- Immutable (Object.assign)
Total elapsed = 2199 ms = 50 ms (read) + 2149 ms (write).

-- Immutable (immutable.js)
Total elapsed = 1690 ms = 638 ms (read) + 1052 ms (write).

-- Immutable (seamless-immutable)
Total elapsed = 91333 ms = 31 ms (read) + 91302 ms (write).

-- Immutable (immutable-assign (created by me))
Total elapsed = 2223 ms = 50 ms (read) + 2173 ms (write).

В идеале, вы должны профилировать свое приложение, прежде чем вводить любую оптимизацию производительности, однако неизменность является одним из тех дизайнерских решений надо решить пораньше. Когда вы начинаете использовать незыблемыми.js, вам нужно использовать его во всем вашем приложении, чтобы получить преимущества производительности, потому что взаимодействие с простыми объектами JS с помощью fromJS() и toJS() очень дорого.

PS: только что узнал, что массив deep freeze'Ed (1000 элементов) становится очень медленным для обновления, примерно в 50 раз медленнее, поэтому вы должны использовать только deep freeze только в режиме разработки. Результаты тестов:

-- Immutable (Object.assign) + deep freeze
Total elapsed = 45903 ms = 96 ms (read) + 45807 ms (write).

оба они не делают объект глубоко неизменным.

, используя Object.freeze вам придется создавать новые экземпляры объекта / массива самостоятельно, и у них не будет структурного совместного использования. Так что каждое изменение, которое потребует глубокого копирования всего, и старая коллекция будет собираться мусор.

immutablejs С другой стороны, будет управлять коллекциями, и когда что-то изменится, новый экземпляр будет использовать части старого экземпляра, которые не изменились, поэтому меньше копирования и сбора мусора.


Object.freeze не делает никакого глубокого замораживания изначально, я считаю, что неизменным.JS, совсем.

то же самое с любой библиотекой - зачем использовать подчеркивание, jquery и т. д.

люди любят повторно использовать колеса, которые другие люди построили : -)


самая большая причина, которая приходит на ум-вне наличия функционального api, который помогает с неизменяемыми обновлениями, - это структурный обмен, используемый неизменяемым.js. Если у вас есть приложение, которое нуждается в принудительной неизменности (т. е. вы используете Redux), то если вы используете только объект.замерзните, и вы будете делать копию для каждой "мутации". Это не очень эффективно с течением времени, так как это приведет к трэсингу GC. С Неизменным.js, вы получаете структурный обмен, запеченный в (как в отличие от необходимости реализации пула объектов/собственной модели структурного обмена), поскольку структуры данных, возвращаемые из неизменяемых, являются попытками. Это означает, что все мутации по-прежнему ссылаются в структуре данных, поэтому ГК пробуксовка сведена к минимуму. Подробнее об этом на Immutable.docsite js (и отличное видео, более глубокое создателем, ли Байроном):

https://facebook.github.io/immutable-js/


Существует несколько основных различий между объектом.замораживания() и неизменяемые.js.

давайте сначала рассмотрим стоимость производительности. Объект.freeze() является мелким. Это сделает объект неизменяемым, но вложенные свойства и методы внутри этого объекта все еще могут быть мутированы. The "объект".заморозить() документация обращается к этому и даже продолжает предоставлять функцию "deepFreeze", которая еще дороже с точки зрения производительности. Неизменный.js с другой стороны будет сделайте объект в целом (вложенные свойства, метод и т. д.) неизменяемым по более низкой стоимости.

кроме того, если вам когда-либо понадобится клонировать неизменяемый объект переменной.freeze() заставит вас создать совершенно новую переменную, при этом неизменяемую.js может повторно использовать существующую неизменяемую переменную для более эффективного создания клона. Вот интересная цитата об этом из в этой статье:

"незыблемыми методами .набор() может быть более эффективным, чем клонирование потому что они позволяют новым ссылочным данным объекта в старом объекте: только измененные свойства отличаются. Таким образом, вы можете сохранить память и производительность против постоянного глубокого клонирования всего."

в двух словах, незыблемыми.js делает логические связи между старыми и новыми неизменяемыми переменными, тем самым улучшая производительность клонирования, а замороженные переменные пространства занимают память. Объект.freeze () к сожалению, нет - каждый раз, когда вы клонируете новую переменную из замороженный объект вы в основном пишете все данные заново, и между двумя неизменяемыми переменными нет логической связи, даже если (по какой-то странной причине) они содержат идентичные данные.

поэтому с точки зрения производительности, особенно если вы постоянно используете неизменяемые переменные в своей программе, неизменяемые.js-отличный выбор. Однако производительность-это еще не все, и есть некоторые большие оговорки к использованию неизменяемых.js. Неизменный.js использует собственную структуру данных, которая делает отладку, или даже просто записывать данные на консоль, королевская боль. Это также может привести к потере основных функций JavaScript (например, вы не можете использовать ES6 de-structuring с ним) Неизменными.документация js печально невозможна для понимания (потому что изначально она была написана для использования только в самом Facebook), требуя много веб-поиска, даже когда возникают простые проблемы.

Я надеюсь, что это покрывает наиболее важные аспекты обоих подходов и поможет вам решите, что будет лучше для вас.