Любое преимущество в производительности для "блокировки" объектов JavaScript?


в JavaScript 1.8.5 (в ECMAScript 5) добавляет некоторые интересные методы, которые предотвратить будущие модификации переданного объекта, с различной степенью тщательности:

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

мой вопрос: в современных двигателях JS, таких как V8, есть ли какое-либо преимущество в производительности (например, более быстрый поиск свойств, уменьшенный объем памяти) при блокировке объектов с использованием вышеуказанных методов?

(см. Также хорошее объяснение Джона отставки – не говоря уже о производительности.)

7 55

7 ответов:

тут без разницы в производительности по крайней мере с Chrome 47.0.2526.80 (64-бит).

Testing in Chrome 6.0.3359 on Mac OS 10.13.4
-----------------------------------------------
Test               Ops/sec
non-frozen object  106,825,468  ±1.08%  fastest
frozen object      106,176,323  ±1.04%  fastest

тест производительности (доступен по адресу http://jsperf.com/performance-frozen-object):

  const o1 = {a: 1};
  const o2 = {a: 1};

  Object.freeze(o2);

  // Non-frozen object:
  for(var key in o1);

  // Frozen object:
  for(var key in o2);

03.05.2018 обновление: нет никакой разницы в производительности на Chrome 66.0.3359 (64-разрядная версия)

обновление 06.03.2017: нет никакой разницы в производительности на Chrome 56.0.2924 (64-разрядная версия)

обновление 13.12.2015: нет никакой разницы в производительности на Chrome 47.0.2526.80 (64-разрядная версия)


С Chrome 34 замороженный объект работает немного лучше, чем незамерзший в тестовом примере @pimvdb (результаты ниже). Разница, однако, не кажется достаточно большой, чтобы оправдать использование этой техники для производительности выгоды.

http://jsperf.com/performance-frozen-object

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  105,250,353  ±0.41%  3% slower
frozen object      108,188,527  ±0.55%  fastest

запуск тестовых случаев @kangax показывает, что обе версии объекта выполняют почти то же самое:

http://jsperf.com/performance-frozen-object-prop-access

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  832,133,923  ±0.26%  fastest
frozen object      832,501,726  ±0.28%  fastest

http://jsperf.com/http-jsperf-com-performance-frozen-object-instanceof

Testing in Chrome 34.0.1847.116 on OS X 10.9.2
----------------------------------------------
Test               Ops/sec
non-frozen object  378,464,917  ±0.42%  fastest
frozen object      378,705,082  ±0.24%  fastest

в Google Chrome (так V8, то есть), замороженный объект повторяется 98% медленнее чем обычный объект.

http://jsperf.com/performance-frozen-object

Test name*              ops/sec

non-frozen object    32,193,471
frozen object           592,726

вероятно, это потому, что эти функции относительно новые и, вероятно, еще не оптимизированы (но это только мое предположение, я честно не знаю причины).

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


* код для теста:

var o1 = {a: 1};
var o2 = {a: 1};

Object.freeze(o2);

тест 1 (незамерзший объект):

for(var key in o1);

Тест 2 (замороженный объект):

for(var key in o2);

EDIT:

так как этот ответ был написан, ошибка в V8, которая вызвала эту проблему была исправлена. Смотрите ответ Яна Молака выше для mor

в теории замораживание объекта позволяет сделать более сильные гарантии о форме объекта.

Это означает, что виртуальная машина может сжать размер памяти.

Это означает, что виртуальная машина может оптимизировать поиск свойств в цепочке прототипов.

Это означает, что любые живые ссылки просто стали не жить, потому что объект может измениться.

на практике JavaScript движки пока не делают эти агрессивные оптимизации.

V8 имеет оптимизированный объект.заморозить состоянию на 20 июня 2013 года. И Возражать.печать и объект.preventExtensions по состоянию на 10 декабря 2014 года. См.https://code.google.com/p/chromium/issues/detail?id=115960

по состоянию на проблема с кодом Google:

разница в производительности обусловлена структурой данных резервного хранилища. Для нескольких свойств дескриптор объекта описывает, где свойства хранятся в массиве свойств. Если количество свойства растут, мы в конечном итоге переключаемся на словарь для поддержки магазин, который является менее производительным, но более гибкий. Когда мы замораживаем объект, что делается, это то, что все свойства установлены в неконфигурируемый и неписаный. Хранение этих атрибутов только возможно в резервном хранилище словаря, поэтому мы переключаемся на это.

EDIT: больше работы было сделано для оптимизации этого и разница между нормальными объектами и замороженными объектами была уменьшена до около 20%. Запечатанные объекты по-прежнему занимают в два раза больше времени для итерации, но работа над этим продолжается.

единственная причина, по которой я вижу эти методы в производственном коде, заключается в том, что вы можете иметь запечатанные или замороженные объекты для целей целостности.

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

также, эти методы легко "прокладка" в среде, которая не знает о них, просто возвращая исходный объект. Конечно, тогда это не возымеет никакого эффекта.

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

Если вы заинтересованы в производительности объекта создание (дословный против замороженными против загерметизированный против Immutable.Map), Я создал