Pull to refresh

JavaScript Performance Best Practices

Reading time4 min
Views11K

Наткнулся на интересный документ в Твиттере.

JavaScript Performance Best Practices


В заголовке указана категория WRT (Nokia Web Runtime or Widget for S60), то есть конкретная Нокиевская платформа, но, думаю, многим интересно будет почитать, возможно найдёте для себя что-то новое. Есть действительно полезные советы, но есть и вредные, особенно в свете современной разработки _под все браузеры_.
Сначала думал оформить как топик-ссылку, но под катом я обращу внимание на некоторые проблемы этой статьи. Статью прочитать стоит но ни в коем случае не относитесь к ней, как к истине в последней инстанции.



Еще раз замечу — эти замечания стоит рассматривать с свете «универсального программирования под все браузеры». Вполне возможно, что в плане разработки под Симбиан статья — предельно истинная

Предлагайте в комментариях свои замечания — может, в итоге это выльется в отличную статью про оптимизацию
Я бы сам отредактировал эту статью в Вики, но «You do not have sufficient privileges to view this page or perform this action.»

Начнём с того, что в статье раскрыто множество действительно полезных советов.
Например, использование eval лучше избегать, а при получении и изменении размеров элемента могут появится излишние reflow (Minimize the use of operations determining the dimensions or location of elements).
Avoid modifications while traversing

А контейнер, который возвращает getElementsByTagName действительно «живой» и следующий код повесит ваш браузер:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Test</title>
	</head>
	<body>
		<div id="container"><em></em><em></em></div>
	</body>
	<script>/* Script here */</script>
</html>

var doc  = document,
    ems  = doc.getElementsByTagName('em'),
    cont = doc.getElementById('container');
for (var i = 0; i < ems.length; i++) {
	cont.appendChild(doc.createElement('em'));
};


Тем не менее, там есть ряд недостатков.

Во-первых, ошибки. Примеры:
Avoid using eval or the Function constructor

addMethod(myObj, 'methodName', function () { 'this.localVar=foo'; });
// =>
addMethod(myObj, 'methodName', function () { this.localVar=foo; });


Load scripts without blocking for faster startup and to show a splash screen

script.onreadstatechange => script.onreadystatechange

И ошибки не синтасического плана, а логического:

var elem = document.getElementById('elem').propertyOne = 'value of first property';
elem.propertyTwo = 'value of second property';
elem.propertyThree = 'value of third property'
// Не эквивалентно, т.к. [elem] будет равен строке 'value of first property', а не dom-элементу
document.getElementById('elem').propertyOne = 'value of first property';
document.getElementById('elem').propertyTwo = 'value of second property';
document.getElementById('elem').propertyThree = 'value of third property';


Во-вторых, хотя некоторые советы действительно ускорят работу вашего приложения — они не имеют смысл, т.к. имеют совершенно другую логику программы.
Попросту говоря, сделайте «Б» вместо «А» потому что «Б» быстрее.

Пример —
Don't use try-catch-finally inside performance-critical functions

Иногда может быть необходима обработка исключений внутри цикла, иногда — снаружи. У этих двух операций совершенно разная основа и разный результат.

Avoid for-in in performance-critical functions

Опять же — разный результат. var i in arr для массивов применимо в крайне редких ситуациях. Самая правильная итерация по массиву (используется в фреймворках):
for (var i = 0, len = arr.length; i < len; i++) if (i in arr) {
   // action
}

Это правильно пройдёт массив, который не полностью заполнен и соответствует поведению метода forEach из последних спецификаций:

var arr = ['zero','one','two'];
arr[10] = 'ten';

arr.forEach(function (elem) {
	console.log(elem); // Выведет "zero, one, two, ten" без семи undefined между "two" и "ten"
});


Если вы знаете содержимое массива и неважно, в каком порядке его обоходить — можно использовать обратный цикл
function sum (arr) {
	var result = 0;
	for (var i = arr.length; i--;) {
		result += arr[i];
	}
	return result;
};

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

Try to keep script comments to a minimum/ Avoid long variable names

Во-первых, в последних версиях современных браузеров есть jit-компиляция, которая делает этот совет неуместным
Во-вторых, в рабочем приложении скрипты сжимаются и комменты вырезаются. а во время разработки такая оптимизация не имеет смысла
В-третьих, комментируйте столько и ровно столько, сколько нужно для правильного понимания этого кода. Какое бы влияние оно не оказывало на производительность — это не важно.

Store local references to out-of-scope variables

Кеширование document имеет смысл, но пример плохой, который в данном случае не имеет смысла, т.к. чтение из кеша происходит только один раз.

Consider using a custom data exchange format for large datasets, as an alternative to XML and JSON

Вредный совет. Постарайтесь максимально избежать сообственных форматов данных и в статье показан пример такого ужаса:
that.contacts = o.responseText.split("\\c");
 
for (var n = 0, len = that.contacts.length, contactSplit; n < len; n++) {
	contactSplit = that.contacts[n].split("\\a");
	
	that.contacts[n] = {};
	that.contacts[n].n = contactSplit[0];
	// ...
	that.contacts[n].y = contactSplit[8];
}

Во-первых, это записывать намного дольше, чем var contacts = JSON.parse(o.responseText);
Во-вторых, парсинг JSON во многих браузерах встроенный и есть вероятность, что ваш «быстрый» формат будет работать намного медленнее, чем JSON. Но может и быстрее, смотрите комментарии.
В-третьих, есть куча недостатков во время поддержки: неочевидное содержимое o.responseText, приходится писать парсер и компилятор формата на сервере и клиенте, сторонние разработчики будут вШоке и т.д.
Основная идея в том, что такая оптимизация крайне редко имеет смысл. В большистве случаев стоит её избежать в силу множества недостатков

В общем, читайте и думайте. Интересные и полезные советы там есть, но всё анализируйте и не используйте бездумно. Как и всегда)
Tags:
Hubs:
Total votes 36: ↑34 and ↓2+32
Comments32

Articles