JavaScript Performance Best Practices


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

    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, приходится писать парсер и компилятор формата на сервере и клиенте, сторонние разработчики будут вШоке и т.д.
    Основная идея в том, что такая оптимизация крайне редко имеет смысл. В большистве случаев стоит её избежать в силу множества недостатков

    В общем, читайте и думайте. Интересные и полезные советы там есть, но всё анализируйте и не используйте бездумно. Как и всегда)
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 32
    • 0
      Почему же всё у всех по-своему… Ни к чему тут такая «индивидуальность». Придерживались бы стандартов, было бы отлично. Комментарий наверное и к посту про сохранение страниц в браузерах тоже относится.
      • +1
        не то окно?)
        • –1
          То… Сначала туда хотел написать, потом прочитал этот пост, понял, что сюда тоже как раз. Вот так хитро и написал, чтобы не засорять базу данных хабрахабра, что может привести к излишним затратам электроэнергии.
          P.S. .WWF
          • +2
            Простите, а к чему в этом топике «индивидуальность»? )
            • 0
              И всё же я чего-то напутал) Это скорей к тому посту
      • +1
        С последним зря вы так категоричны. Очень рекомендую книгу high performance web sites.
        • +1
          <s>web sites</s> javascript
          oreilly.com/catalog/9780596802806
          • +1
            Спасибо, а она отличается содержимым от High Performance Web Sites?
            • 0
              да, в ней описано больше техник оптимизации. по сути в hpws в разделах, посвященных javascript есть только отрывки из первой. и, главное, донесено что именно нужно оптимизировать, а что нет.
          • +1
            Я так понимаю, вы про совет «Постарайтесь максимально избежать сообственных форматов данных и в статье показан пример такого ужаса:»?
            На самом деле я не уверен, что встроенный парсер JSON, который начал появлятся в середине 2009-го года в браузерах, но уже крайне актуальный будет медленнее чьего-то «велосипедного» формата. Но спорить не буду.

            На самом деле, я критически отношусь к этому вопросу больше из-за сложности поддержки, дублировании излишнего кода на сервере и клиенте.

            И подозреваю, что, таки, совет не актуальный в Фоксе3.5+, Хроме, последних Операх и ИЕ8+.
            • 0
              [].split тоже нативный. а насчет поддержки это да, но собствтвенно, оптимизация производительности это рефакторинг наоборот, поэтому поддержка усложняется сознательно.
              • +1
                Регекспы тоже нативные. Вопрос, что быстрее — 50 вызовов split в цикле, или один вызов json-encode
                • 0
                  я не говорю, что свое быстрее всегда. есть ситуации, где «свое» быстрее и дешевле по трафику, поэтому однозначно причислять совет к вредным не стоит, хотя в 99.9% случаев действительно лучше пользоваться стандартным форматом.
                  • +1
                    тут есть еще вопрос, почему они не сделали так:

                    that.contacts[n] = {
                    	n : contactSplit[0],
                    	// ...
                    	y : contactSplit[8]
                    }
                    


                    • +1
                      что тоже есть одним из советов.

                      или даже так (associate из Mootools):
                      that.contacts[n] = contactSplit[0].associate('n', /* ... */, 'y');
                      

                      Что хоть более читаемо, хоть и незначительно медленнее.

                      На самом деле я считаю, что советы «напишите свою хрень в 50 строк, которая возможно будет чуточку быстрее» есть однозначно вредными. Тем более, так авторитетно заявленные. Подобные вещи надо делать (а тем более советовать) предельно осторожно и когда точно знаешь, что такая «оптимизация» будет во благо, а не в зло
                      • +1
                        тем более, что такой способ не позволит передавать многие вещи аджаксом, например, если пользователь напишет:
                        Я устоновил игрушку в e:\cosmos\arcade\game, а она не запускается
                        и мы постараемся подобным запросом джсоном получить это сообщение — всё поломается. изредка, мы точно знаем формат данных, но часто такие оптимизации могут вылиться еще и кучей багов.
                        • +1
                          *не джосном а аджаксом
                          • 0
                            будьте внимательнее :)
                            я еще раз повторю: я не говорю, что это правило, которое всегда верно. но есть ситуации, где можно передать данные своим форматом и это сэкономит 200 байт и 0,01 секунды на запрос, а в рамках какого-нибудь сервиса это 1 миллион долларов в год, что превышает издержки на поддержку такого «оптимизированного» участка кода.
                            • +1
                              абсолютно согласен с вами)

                              но подобные статьи рассчитаны на совершенно другой уровень разработчиков, а новички будут ошибочно считать, что JSON — должен умереть, потому что он медленный
                  • +1
                    я не утверждаю, что сплит быстрее или медленнее, я предполагаю, что это может быть мало того, что трудноподдерживаемым, так еще и не иметь смысле в силу последних изменений в браузерах
              • +2
                В заголовке указана категория WRT (Nokia Web Runtime or Widget for S60)
                Т.е. речь про конкретную нокиевскую платформу, а не общие рекомендации для всех случаев.
                Там может и JSON тормозит и нету jit и другие прелести мобильной платформы.
                • +1
                  а главного то я и не заметил. спасибо, сейчас исправлю топик
                • +1
                  В заголовке указана категория WRT (Nokia Web Runtime or Widget for S60)
                  Т.е. речь про конкретную нокиевскую платформу, а не общие рекомендации для всех случаев.
                  Там может и JSON тормозит и нету jit и другие прелести мобильной платформы.
                  • 0
                    Вы случайно отпостили два раза с разницей в 4 минуты?
                    • +1
                      хабра глючит
                      • +1
                        был напуган
                        • +1
                          не случайно, хабр лежал с 500й ошибкой, сделал паузу, посмотрел в соседнем окне, что коммента не появилось и попробовал еще раз и так раза 4
                      • 0
                        — Consider using a custom data exchange format for large datasets, as an alternative to XML and JSON

                        — Крайне вредный совет. Постарайтесь максимально избежать сообственных форматов данных.

                        Автор оригинальной статьи приводит ссылку на:
                        code.flickr.com/blog/2009/03/18/building-fast-client-side-searches/
                        где сравниваются скорость загрузки данных с помощью разных форматов и объясняется, где и когда лучше его использовать. Так что совет совсем не вредный, а гибкий, аргументированный и подкреплен примерами.
                        • +2
                          статья за March 18th, 2009. И уже неактуальна. Потому что встроенное декодирование ЖСОН появилось:
                          * Mozilla Firefox 3.5+ — июнь, 2009 года
                          * Microsoft Internet Explorer 8 — 2009 года
                          * Браузеры, основанные на WebKit (например, Google Chrome, Apple Safari) — я так понимаю, где-то в 2009-году, до июня
                          * Opera 10.5+

                          То есть все современные и даже многие устаревшие браузеры имеют встроенную реализацию, о которой в Марте 2009-ого было еще неизвестно.
                          • +1
                            Соглашусь с аргументом, но точку в этом вопросе поставят результаты актуального теста.
                            • +1
                              тесты показали, что я — неправ. сейчас обновлю топик
                              fx 3.5.11
                              json : 116ms
                              plain: 53ms

                              chrome 7.0.517.41 beta
                              json : 162ms
                              plain: 33ms
                        • 0
                          мне одному кажется что заголовок смахивает на Node.js

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