Подтвердить что ты не робот

Javascript-профилирование тайны - замыкающие переменные

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

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

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

Может ли кто-нибудь поделиться некоторой ясностью здесь?

SOME = function(){};
SOME.prototype.exe = function(v){
	var x = {
		a:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
		b:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
		c:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	};
	return x[v];
};

SOME2 = function(){};
SOME2.prototype.exe = function(v){
	return this.exes[v];
};
SOME2.prototype.exes = {
	a:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	b:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	c:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
};
SOME_FN = function(){};
SOME_FN.prototype.exe = function(v){
	var x = {
		a: function(p){this.p1 = p;return this;},
        b:function(p){this.p2 = p*3;return this;},
        c:function(p){this.p3 = p*99;return this;},
    };
  return x[v].call(this,42);
};

SOME_FN2 = function(){};
SOME_FN2.prototype.exe = function(v){
    return this.exes[v].call(this,42);	
};
SOME_FN2.prototype.exes = {
    a: function(p){this.p1 = p;return this;},
    b:function(p){this.p2 = p*3;return this;},
    c:function(p){this.p3 = p*99;return this;},
};

var a1 = a2 = a_fn1 = a_fn2 = [];
	

var run_local_obj = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x1 = new SOME();
		x1.exe('a');
		a1.push(x1);
	}
};
var run_proto_obj = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x2 = new SOME2();
		x2.exe('a');
		a2.push(x2);
	}
};
var run_local_fn = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x1 = new SOME_FN();
		x1.exe('a');
		x1.exe('b');
		x1.exe('c');
		a_fn1.push(x1);
	}
};
var run_proto_fn = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x2 = new SOME_FN2();
		x2.exe('a');
		x2.exe('b');
		x2.exe('c');
		a_fn2.push(x2);
	}
};
<button onclick="run_local_obj(this)">local obj</button>
<button onclick="run_proto_obj(this)">proto obj</button>
<button onclick="run_local_fn(this)">local obj FN</button>
<button onclick="run_proto_fn(this)">proto obj</button>
4b9b3361

Ответ 1

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

Если я запускаю эти тесты поочередно (щелкая по кнопкам и просматривая временную шкалу), то для каждого следующего запуска результаты сильно отличаются. Из нескольких прогонов это выглядело как третий (run_local_fn) обычно длиннее других.

Затем я попытался запустить их в обратном порядке (нажмите кнопки от 4 до 1) и получил совершенно другой результат - run_local_obj был самым длинным.

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

Полный код здесь, вы можете клонировать репо и тестировать его локально.

Вот как я запускаю каждый тест в Chrome (я запустил его с помощью python -m SimpleHTTPServer 8082 внутри папки js-perf-test):

  • Откройте вкладку http://localhost:8082/perf.html, откройте инструменты для разработчиков
  • Запустить запись временной шкалы
  • Нажмите кнопку
  • Дождитесь результатов в консоли (мин/макс/средний)
  • Остановить запись временной шкалы

Результаты стабильны и повторяемы (как тайминги, так и временные рамки), вот один из тестов:

Итак, что мы видим здесь:

1) run_proto_obj является самым быстрым, а run_local_obj близок к нему.

Я думаю, что для run_proto_obj ожидается, что он будет наиболее эффективным, так как он использует статически определенный объект со строками. И JS-движок, вероятно, может оптимизировать run_local_obj, поэтому объект x повторно используется и не создается каждый раз.

2) run_local_fn является самым медленным.

Здесь мы имеем локальный вычисление объектов и динамических строк x, больше floating частей, чем в других тестах.

3) run_proto_fn быстрее, чем run_local_fn, но медленнее, чем первые две функции.

Я думаю, что это также ожидается, объект с a, b, c определяется только один раз (поэтому он быстрее, чем run_local_fn).

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

Итак, вернемся к вашему вопросу:

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

Он выглядит так, как будто вы просто не правильно настроили эксперимент. Согласно вышеприведенным результатам, run_proto_obj на самом деле самый быстрый.

Обновление: я просто попробовал тот же тест в Firefox, результаты похожи:

  • `run_local_obj '- 344.85мс
  • `run_proto_obj '- 151.47мс
  • `run_local_fn '- 788.08мс
  • `run_proto_fn '- 265.21мс

run_proto_obj является самым быстрым, а run_local_fn является самым медленным.