Любое преимущество в производительности для "блокировки" объектов JavaScript?
в JavaScript 1.8.5 (в ECMAScript 5) добавляет некоторые интересные методы, которые предотвратить будущие модификации переданного объекта, с различной степенью тщательности:
по-видимому, основной смысл этого заключается в том, чтобы поймать ошибки: если вы знаете, что не хотите изменять объект после определенной точки, вы можете заблокировать это вниз, так что ошибка будет выброшена, если вы случайно попытаетесь изменить его позже. (При условии, что вы сделали "use strict";
что есть.)
мой вопрос: в современных двигателях JS, таких как V8, есть ли какое-либо преимущество в производительности (например, более быстрый поиск свойств, уменьшенный объем памяти) при блокировке объектов с использованием вышеуказанных методов?
(см. Также хорошее объяснение Джона отставки – не говоря уже о производительности.)
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
), Я создал