Почему фабрики / замыкания JS намного медленнее, чем конструкторы / прототипы?

Когда-то фабрики / закрытия в JS были в пределах 15% от конструкторов / прототипов. Сегодня разница составляет более 8000% в пользу прототипов (а прототипы используют примерно половину памяти).

https://jsperf.com/prototype-vs-factory-performance/4

Замыкания (теоретически) не создают дополнительных объектов. У вас есть замыкание и экземпляр вместо прототипа и экземпляра (и у замыканий есть еще одно преимущество, потому что вы не можете добавлять / удалять из них свойства). Мой единственный вывод состоит в том, что, хотя функции являются примитивами и неизменяемыми (хотя объекты функций - нет), они не интернированы, что приводит к скачкам в кэше инструкций. Эта разница проявляется в JS-движках.

Есть ли у кого-нибудь реальные факты о том, почему существует такое огромное несоответствие?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
45
1

Ответы 1

Closures (in theory) don't create more objects.

Этот стиль создания объекта «закрытие / фабрика» действительно создает больше объектов: с использованием прототипов экземпляры методов прототипа являются общими, тогда как в «фабричном» стиле каждый экземпляр объекта получает свою собственную копию всех методов. Это наблюдаемо, так что это не то, что движок может просто оптимизировать. Учитывать:

var x1 = createValueObject();
var x2 = createValueObject();
x1.get.my_tag = 42;
console.info(x2.get.my_tag);      // undefined
console.info(x2.get === x1.get);  // false

var y1 = new ValueObject();
var y2 = new ValueObject();
y1.get.my_tag = 123;
console.info(y2.get.my_tag);      // 123
console.info(y2.get === y1.get);  // true

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


https://jsperf.com/prototype-vs-factory-performance/4

Это также отличный пример: Остерегайтесь вводящих в заблуждение микробенчмарков!

Каждый раз, когда вы видите сотни миллионов операций в секунду в тесте jsperf.com, значит, оптимизирующему компилятору почти наверняка удавалось исключить весь ваш код, и вы измеряете пустые циклы. Никакая реальная операция не работает так быстро.

В данном случае это не удивительно: использование прототипов - это идиоматический способ определения / создания объектов в JavaScript в, и движки вкладывают много усилий в оптимизацию каждого аспекта этого шаблона, поэтому современные движки имеют возможность отслеживать, какие методы прототипа получают. вызывается, в конечном итоге встраивает их (не сразу, только в горячий код!), выясняет, что они не дают полезных результатов, и отбрасывает весь бесполезный код.

При правильном и тщательном тестировании я ожидал, что то, что вы называете шаблоном «конструкторы / прототипы», по-прежнему будет значительно быстрее, но не так быстро, как ошибочно показывают текущие результаты.


instruction cache thrashing

Нет, кеш инструкций тут ни при чем.

Once upon a time, factories/closures in JS were within 15-ish percent of constructors/prototypes.

Мне трудно поверить, что так было в любое время за последние десять лет. Может быть, 20 лет назад, когда все было по-собачьи?

Зачем нужны копии функций? Разве указатель на интернированную функцию не позволит использовать одну и ту же функцию для разных объектов? Поскольку форма результирующих литералов идентична и встречается в одной и той же точке кода, не должно ли быть возможным совместное использование скрытого класса? Если вы повторяете десятки идентичных функций с разными участками памяти, постоянно меняя местами кеш-память, разве это не перегрузка кеша по сравнению с повторным запуском одних и тех же 5-6 функций?

Elijah Dorman 28.12.2018 20:47

Как показывает фрагмент кода, наличие копий объектов функций можно наблюдать (программы могут полагаться на это); другими словами, спецификация JavaScript требует наличия копий. Их код будет совместно использоваться в большинстве движков (следовательно, без эффектов кеширования инструкций), но объекты должны быть отдельными. Скрытые классы не меняют этого.

jmrk 30.12.2018 21:08

Другие вопросы по теме