Подтвердить что ты не робот

Почему я должен использовать immutablejs над object.freeze?

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

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

4b9b3361

Ответ 1

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

Без просто повторения docs и инструкция миссии, Я сформулирую две вещи, которые он предоставляет:

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

  • Все их типы реализованы как Persistent Data Structures.

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

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

Я настоятельно рекомендую вам прочитать статьи и видеоролики, на которые они ссылаются, и многое другое о Persistent Data Structures (так как это то, что касается immutablejs), но я подведу итог в предложении:

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

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

  x: 4,
  y: 10
};

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

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

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

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

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

Неизменяемые обертывания для вас:

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

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

И благодаря ノ * ✧ ゚ магии ✧ ゚ * ヽ постоянных структур данных они обещают сделать наименьшее количество операций.

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

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

Ответ 2

Согласно моим эталонам, immutable.js оптимизирован для операций записи, быстрее, чем Object.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).

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

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