У меня ничего не тормозит. Я ACMщик и хочу понимать с чем работаю
Тогда берем ноду, запускаем скрипт с флагами —print-opt-code и —code-comments и изучаем ассемблерный код в который будет скомпилирован js.
Вот например почему лучше не юзать наследование в js когда количество сабклассов больше 4
Есть такой бенчмарк
class Animal {
constructor() {
this.done = 0
}
doIt() {
this.done++
}
}
class Cat extends Animal { }
class Dog extends Animal { }
class Monkey extends Animal { }
class Bird extends Animal { }
class Bear extends Animal { }
function testAnimals(animals) {
for (let i = 0; i < animals.length; i++) {
for (let j = 0; j < 100000; j++) {
animals[i].doIt();
}
}
}
setInterval(() => {
const cat = new Cat();
const dog = new Dog();
const monkey = new Monkey();
const bird = new Bird();
const bear = new Bear();
const time = Date.now();
testAnimals([cat, dog, monkey, bird, bear]);
console.log(Date.now() - time, cat.done, dog.done, monkey.done, bird.done, bear.done);
}, 1000);
Где мы создаем 5 сабклассов класса Animal и тестируем время работы икремента свойства на базовом классе
Получаем цифры примерно
23 100000 100000 100000 100000 100000
24 100000 100000 100000 100000 100000
24 100000 100000 100000 100000 100000
25 100000 100000 100000 100000 100000
23 100000 100000 100000 100000 100000
Но если мы уберем один сабкласс (заменим объект bear на объект bird2, то есть количество операций не меняется)
//const bear = new Bear();
const bird2 = new Bird();
const time = Date.now();
testAnimals([cat, dog, monkey, bird, /* bear */ bird2]);
console.log(Date.now() - time, cat.done, dog.done, monkey.done, bird.done, /* bear.done */ bird2.done);
То мы уже получим такие цифры (почти в 10 раз быстрее)
3 100000 100000 100000 100000 100000
3 100000 100000 100000 100000 100000
3 100000 100000 100000 100000 100000
3 100000 100000 100000 100000 100000
Чем это объясняется? Достаточно взглянуть на ассемблерный вывод (если запустить этот скрипт с флагами --print-opt-code и --code-comments)
В первом случае мы видим что в ассемблере есть инструкции call c вызовом рантайм функций LoadIC_Megamorphic и StoreIC а во втором случае этих call-инструкций вообще нет то есть инкремент свойства заинлайнился прямо в ассемблер.
В связи с этим делаем вывод что v8 не умеет в true-наследование (как это умеет делать c++ через v-table) а просто харкодит скрытые классы наследников и как только их становится больше 4-х то он компилирует в медленный дженерик код все обращения к полям базового класса