Почему отличается время перебора объектов одного класса от множества классов?

Из-за ошибки возникла ситуация, которую очень хотелось бы понять. Время на цикл (50 тыс итераций) перебора и обращение к свойствам экземпляров одного класса существенно отличается от времени перебора экземпляров разных классов. 2 мс против 40мс.

Возможно у кого нибудь будут мысли о причинах такого поведения.

Код:

let length = 50000;

let list_of_one = [];
let main_class = getClass();

for(let i = 0; i<length;i++){
  list_of_one.push(new main_class()) 
}

let list_of_many = [];
for(let i = 0; i<length;i++){
  let main_class = getClass()
  list_of_many.push(new main_class())
}


performanceTest(list_of_one)  // результат ~2ms
performanceTest(list_of_many)  // результат ~40ms

function performanceTest(list){
 console.time('time')
  let c = list.length
  for(let i = 0; i<c;i++){
        list[i].buffer_data_calc.color[3] = i
  }
  console.timeEnd('time')
}


function getClass(){
 class Main {
   id=23;
   type= 1;
   buffer_data_calc={color:[1,2,3,4,5]};
   init(){

   }
 }
    return Main
}

p.s было замечено что уже на поиск свойства buffer_data_calc уходит большая времени...

JS Fiddle


Ответы (2 шт):

Автор решения: Aziz Umarov

Почему вы считаете что в цикле у вас одинаковые операции. Дело в том что в первом случае вы подготовили класс и в цикле добавляете новые экземпляры этого класса. Но во втором случае вы генерирует новый класс в цикле дополнительно, что не может не занимать время и только потом создаёте новый экземпляр класса. Проверьте на примере явно созданный 5-10 классов и добавьте их в цикле. Я не думаю что в этом будет существенная разница.

На счёт теста. У вас не однородный и однородный массивы. Понятно чтоб получить свойство в однородном будет быстрее нежели постоянно узнавать в различном.

→ Ссылка
Автор решения: Qwertiy

Есть 2 момента.

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

И второй момент, касающийся именно приведённого примера. При доступе к свойствам есть обычный доступ, а есть доступ при котором уже известно, в каким сдвигом оно записано. Браузер старается в большинстве случаев использовать второй, поскольку он быстрее. Но в твоём массиве вообще все объекты разных классов - скорее всего при таком массиве браузер откажется от второго варианта и будет использовать первый. Если сократить число классов до 2 (или нескольких), то ситуация может измениться.

PS: Ответ полностью основан на моих предположениях и знаниях. Я не пытался компилировать и исследовать приведённый код, чтобы дать более детальный и/или точный ответ по нему.

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

→ Ссылка