2016-04-19 3 views
19

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

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

+1

'Object.freeze()' отлично подходит для обертывания и обучения вашему мозгу концепцией неизменяемых состояний при использовании традиционных структур данных, но этот подход не принесет преимуществ производительности того, что приносит immutablejs. – Kujira

+1

Object.freeze() не делает глубокое замораживание, вы можете использовать https://github.com/substack/deep-freeze для этого. Проблема в том, что обновление замерзающего объекта становится утомительным, особенно для вложенного объекта, например, Object.assign ({}, freezedObj, { a: 1, b: Object.assign ({}, freezedObj.b, {c : 2}) }); Вы можете проверить https://github.com/engineforce/ImmutableAssign, который является легким неизменным помощником, который может быть просто выше назначения. – engineforce

ответ

31

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

Без простого повторения их docs и mission statement, я сформулируем две вещи, которые она предоставляет:

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

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

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

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

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

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

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

    x: 4, 
    y: 10 
}; 

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

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 ing объект Достаточно Хорошо. Черт, большую часть времени это больше чем достаточно. Это полезная библиотека, которая имеет свою нишу, просто не увлекайтесь рекламой.

+0

Отличный ответ! Спасибо. – alisabzevari

+1

Отличный ответ. Также обратите внимание, что, хотя в ТЕОРИИ структурный обмен делает вещи более эффективными, immutableJS должен нести вес своего кода инфраструктуры, все это не всегда легко оптимизируется JS-двигателями. Это означает, что неизменяемость JS будет иногда намного медленнее, использовать больше памяти и создавать аналогичное давление GC. Более того, вы можете использовать lib, который только заморозит объекты в режиме разработки и оставьте их как есть в режиме производства для еще большей эффективности. – AlexG

+0

Подчеркивание обмана! Это точно. – ohager

1

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

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

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

+0

Написание deepFreeze довольно просто: https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze – alisabzevari

+0

@alisabzevari true, но зачем перестраивать колесо? :-) – Tuvia

+3

Может быть, я хочу узнать больше о колесах – rlemon

1

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

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

2

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

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

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

4

По моим benchmarks, 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). 
0

Существует несколько основных отличий между Object.freeze() и immutable.js.

Сначала рассмотрим стоимость исполнения. Object.freeze() неглубоко. Это сделает объект неизменным, но вложенные свойства и методы внутри указанного объекта все еще могут быть мутированы. Object.freeze() documentation обращается к этому вопросу и даже продолжает предоставлять функцию «глубокого замораживания», что является еще более дорогостоящим с точки зрения производительности. С другой стороны, Immutable.js сделает объект в целом (вложенные свойства, метод и т. Д.) Неизменным по более низкой цене.

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

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

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

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

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

+0

Пожалуйста, правильно различайте неизменяемые переменные (' const') и неизменяемые значения (примитивы, замороженные объекты, экземпляры, не подлежащие уничтожению) – Bergi

+0

Ваш первый абзац на самом деле не имеет смысла. Как Immutable.js может пересечь вложенный объект более эффективно, чем функция глубокого замораживания? – Bergi

+0

Объекты и массивы не являются примитивными типами данных. Таким образом, объявление их с помощью 'const' не сделает их неизменяемыми, поэтому использование' const' для их замораживания не является опцией (документация 'const 'объясняет это довольно хорошо). Вы также должны прочитать мой первый параграф. Я никогда не писал, что Immutable.js проходит их более эффективно, я написал, что он более эффективен, чем «deepFreeze()» при глубоком замораживании. – Nadav