Наш чат в Telegram для обмена идеями, проектами, мыслями, людьми в сфере ИТ г.Ростова-на-Дону: @it_rostov

Оптимизация javascript скриптов

Сжатие скриптов

    Два альтернативных сервиса, позволяющие сжать ваши скрипты.
  • Bananascript.com - наилучшее сжатие до 72%.
  • Dean Edwards - более известный, но жмет хуже.

Одно важное замечание - при подключении скриптов, созданных этим инструментом, обязательно указывать кодировку для скриптов ISO-8859-1:

<script src="banana.js" charset="ISO-8859-1" type="text/javascript"></script>

Статья на webo.in на тему жать или не жать. Для форматирования Javascript можно воспользоваться JSLint или через локальную версию.

Анализ скорости загрузки страницы

Для анализа вы можете воспользоваться одним из следующих сервисов:
  • The Firefox web-developer toolbar позволяет проанализировать размеры всех загруженных на странице файлов (клик правой кнопкой мыши > Web Developer > Information > View Document Size).
  • Расширение к Firebug позволяет посмотреть на список файлов: на вкладке "Net"
  • OctaGate SiteTimer, который предоставляет online-диаграмму загрузки всех файлов на странице

Сначала HTML, потом Скрипты

Размещаете по возможности JavaScript в конце HTML-файлов. Это позволит всему остальному содержанию страниц (картинкам, таблицам, тексту) загрузиться и отобразиться в первую очередь. Пользователь увидит, что страница загрузилась. После этого большие JavaScript-файлы могут начать загрузку.

Используйте отложенную загрузку JavaScript.

Кеширование

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

Циклы

Оптимизация логического сравнения при итерациях цикла. Рассмотрим обычный цикл for:
for (var i = 0; i < aList.length; i++) {
    // тело цикла
}
Оптимизируем его за счет присвоения размера массива в переменную и инициализация счетчика объединены в одном выражении:
// переменная len будет хранить длину массива
for (var i = 0, len = aList.length; i < len; i++) {
    // тело цикла
}
Дальнейшая оптимизация такого цикла возможна путем прохода его в обратном порядке (если это допустимо). В этом случае, при каждой итерации мы будем сравнивать счетчик с константой, а не переменной, и объединеним выражения сравнения и декремента:
for (var i = aList.length; --i >= 0;) {
    // тело цикла
}

Хаки

if...else
// Скучно
if (success) {
obj.start();
} else {
obj.stop();
}

// Красиво
var method = (success ? 'start' : 'stop');
obj[method]();
соединение строк
['first', 'name'].join(' '); // = 'first name';
['milk', 'coffee', 'suger'].join(', '); // = 'milk, coffee, suger'
оператор «по умолчанию» - ||

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

// возвращает  'No name' когда myName пусто (null или undefined)
var name = myName || 'No name';


// либо options нам передано, либо инициализируем его пустым объектом
var doStuff = function(options) {
  options = options || {};
  // ...
};
охранный оператор &&

Подобно оператору «по умолчанию», он необычайно полезен. Он позволяет избавиться практически от всех IF и делает код намного приятней.

// Скучно
if (isThisAwesome) {
  alert('yes'); // it's not
}

// Прикольно
isThisAwesome && alert('yes');

// Так же полезно для подстраховки
var aCoolFunction = undefined;
aCoolFunction && aCoolFunction(); // не запустится, но и не вылетит с ошибкой
замер времени выполнения части javascript - кода

Вам интересно узнать, что быстрее: цикл с i++ или с i--. Вы можете воспользоваться выводом результатов замера времени в консоль. Это бывает полезно, если надо узнать скорость выполнения операций, блокирующих событийный цикл.

var a = [1,2,3,4,5,6,7,8,9,10];

console.time('testing_forward');
for (var i = 0; i < a.length; i++);
console.timeEnd('testing_forward');
// вывод: testing_forward: 0.041ms

console.time('testing_backwards');
for (var i = a.length - 1; i >= 0; i--);
console.timeEnd('testing_backwards');
// вывод: testing_backwards: 0.030ms
отладка - debugger

вставляете команду debugger в код и отладчик остановится на этой строке

var x = 1;
debugger; // Здесь мы остановимся
x++;


var x = Math.random(2);
if (x > 0.5) {
  debugger; // Условная точка останова...
}
x--;
простой шаблонизатор

работает до тех пор пока в имени свойства переданного объекта не встретится регэкспа. Принимает на вход строку вида 'Hi, my name is {first-name} and my twitter screen name is @{screen-name}' и объект вида {'first-name': 'Василе', 'screen-name': 17}

getTemplated: function( text, replacements ){
    for( var i in replacements )
        replacements.hasOwnProperty( i ) &&
            ( text = text.split('{' + i + '}').join(replacements[i]) );

    return text;
}

другой вариант

function t(tpl, data) {
     return tpl.replace(/\{(.*?)\}/g, function(str, a) { return data[a] || ''; });
}

пример использования шаблонизатора

var action = '/sendForm',
    i18nLogin = 'Введите логин',
    myPrettyForm = [
        '<form action="', action, '" method="POST">',
        '<fieldset>',
            '<input type="email" placeholder="', i18nLogin,'"/>',
            '<input type="submit" />',
            '</fieldset>',
        '</form>'
    ].join('');

Эти шаблонизаторы в две строчки обладают фатальным недостатком: Это многократная замена. И, как следствие, зависящая от порядка выполнения подстановок.

var tpl = "{alfa} and {beta} sat on the tube";
var txt = tpl;
txt = txt.replace("{alfa}", "A{beta}Z"); // "A{beta}Z and {beta} sat on the tube"
txt = txt.replace("{beta}", "B"); // "ABZ and B sat on the tube

txt = tpl;
txt = txt.replace("{beta}", "B"); // "{alfa} and B sat on the tube"
txt = txt.replace("{alfa}", "A{beta}Z"); // "A{beta}Z and B sat on the tube

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

function substitute(tpl, dict)
{
    var f = function(g0, g1, ofs, s)
    {
    if(g1 in dict)
      return dict[g1]; // substitute
    else
      return g0; // leave as-is
    };
    return tpl.replace(/{([^}]+)}/g, f);
}

var s;
s = substitute("{mama} myla {ramu} - {bahama} {mama}", {mama:"MAMA", bahama:"BAHAMA"}); // MAMA myla {ramu} - BAHAMA MAMA
s = substitute("{alfa} and {beta} sat on the tube", {alfa:"A{beta}Z", beta:"B"}); // A{beta}Z and B sat on the tube
генератор пароля
Math.random().toString(36).substr(2)
Приведение к boolean: !!x
x=!!x  // Приведение к boolean