Дать Быстро, эффективно использует память JavaScript

JavaScript системах, таких как Google, V8 (Chrome, Node) предназначены специально для быстрый execution больших приложений JavaScript.Как развиваться, если вы заботитесь о использовании памяти и производительности, вы должны быть осведомлены о некоторых из what’ творится в вашем user’ S browser’ S JavaScript двигателя за scenes.

Будь то V8, SpiderMonkey (Firefox), Carakan (Opera), Chakra (IE) или что-то еще, это может помочь вам лучше оптимизировать applications.That’ S Нельзя сказать, следует оптимизировать для одного браузера или двигателя.Никогда не делайте that.

Вы должны, однако, спросить себя такие вопросы, как:

  • ? Есть ли что-нибудь, что я мог бы делать более эффективно в моем коде
  • Что (общий) оптимизаций у популярных поисковых JavaScript сделать
  • Что такое двигатель не в состоянии оптимизировать, и сборщик мусора в состоянии очистить то, что я ожидал, что он

Dashboard Speedometer Быстрая загрузка веб-сайтов — как быстрые автомобили — требуют использования специальных инструментов.Изображение с сайта: dHybridcars

.

Есть много распространенных ошибок, когда дело доходит до написания памяти эффективный и быстрый код, и в этой статье мы собираемся исследовать некоторые тест-обоснованных подходов для написания кода, который выполняет better.

Итак, как же JavaScript V8 Работа в

В то время как it’ с возможным разработку крупномасштабных приложений без полного понимания двигателей JavaScript, любой автовладелец скажет вам, they’ ве заглянул под капот по крайней мере, один раз.В Chrome мой браузер выбора, I’ м поговорим немного о его двигатель JavaScript.V8 состоит из нескольких основных pieces.

  • база compiler, который анализирует ваши JavaScript и генерирует машинный код перед его выполнением, а не выполнения байт-кода или просто его интерпретации.Этот код изначально не очень optimized.
  • V8 представляет свои объекты в Объект model.Объекты представлены в виде ассоциативных массивов в JavaScript, но в V8 они представлены с скрытая classes, которые являются внутренними тип системы для оптимизации lookups.
  • Выполнения profiler. Следит за их запуска и определяет “горячих” функций (т. е. код, который заканчивает проводить долгое время работает)
  • Оптимизация compiler. Перекомпилирует и оптимизирует “горячих” Код определенных профайлер выполнения, и выполняет оптимизацию, такие как встраивание (т.е. заменить сайта вызова функции с телом абонента)
  • V8 поддерживает deoptimization означает, оптимизирующий компилятор может выручить код генерируется, если она обнаруживает, что некоторые из предположений, он составил около оптимизированный код был слишком optimistic.
  • Он имеет мусор collector.Понимание того, как она работает может быть столь же важны, как и оптимизированный JavaScript.

Garbage Collection

Сборка мусора форма памяти management.It’ где мы есть понятие коллектор, который пытается вернуть память, занятую объектами, которые больше не используются.В сбора мусора языка, таких как JavaScript, объекты, которые по-прежнему ссылается ваше приложение не убраны up.

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

Garbage collection attempts to reclaim memory. Вывоз мусора пытается вернуть память.Изображение с сайта:. Valtteri Mäki

It’ не возможно заставить мусора в JavaScript.Вы wouldn’ хотите, чтобы это сделать, потому что процесс сборки мусора находится под контролем выполнения, и он вообще знает лучше, когда вещи должны быть очищены up.

De-ссылок Misconceptions

В немало дискуссий в Интернете о рекультивации памяти в JavaScript, delete ключевое слово воспитан, как, хотя это должно было быть использована только для удаления ключи от карты, некоторые разработчики думаю, что вы можете заставить де-ссылками использования.Избегайте использования delete, если можно.В приведенном ниже примере, delete o.x делает гораздо больше вреда, чем пользы за кулисами, как он меняется o ‘ с скрытые класса и делает его общий медленный object.

var o = { x: 1 }; 
delete o.x; // true 
o.x; // undefined

Тем не менее, вы почти наверняка найдете ссылки на delete во многих популярных библиотек JavaScript – него есть цель в языке.Основной вынос здесь, чтобы избежать изменения структуры горячих объектов во время выполнения.Наличие системы могут обнаружить такую ​​“ hot” объектам и пытаются оптимизировать их.Это легче, если object’ Структура компании doesn’ T сильно измениться за время своего существования и delete могут вызватьтакие changes.

Есть также неверные представления о путях null работ.Установка ссылки на объект null doesn’ т “нулевой” объекта.Он задает ссылку на объект null.Использование o.x = null лучше, чем при использовании delete, но it’ наверное, даже не necessary.

var o = { x: 1 }; 
o = null;
o; // null
o.x // TypeError

Если эта ссылка была последней ссылки на объект, объект, то право на сбор мусора.Если ссылка не была последней ссылки на объект, объект достижим и не будет мусора collected.

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

var myGlobalNamespace = {};

Globals очищаются, когда вы обновите страницу, перейдите на другую страницу, вкладки или закрыть браузер.Функция-контекстные переменные себя в порядок, когда переменная выходит из области видимости.Когда функции вышли и там aren’ т больше ссылок на него, переменная очищается up.

Правила Thumb

Чтобы дать сборщику мусора шанс собрать столько объектов, сколько возможно как можно раньше, don’ T держаться за объекты, которые вы больше не need.В основном, это происходит автоматически, вот несколько вещей, чтобы иметь в mind.

  • Как упоминалось ранее, лучшая альтернатива ручной де-ссылок является использование переменных с соответствующей сферы.То естьвместо глобальных переменных that’ S обнуляются в аренду, просто использовать функцию локальной переменной, которая выходит за рамки, когда it’ S больше не нужны.Это означает, чистый код с меньшим беспокоиться about.
  • Убедитесь, что you’ повторной отмены привязки обработчиков событий, где они больше не требуется, особенно когда DOM объекты they’ Re связаны с собираешься быть removed
  • Если you’ повторное использование кэша данных локально, убедитесь, чтобы очистить этот кэш или использовать механизм старения, чтобы избежать больших кусков данных, хранящихся что you’ повторно вряд ли reuse

Functions

Следующее, let’ посмотрим на функции.Как we’ уже говорил, сбор мусора работы по рекультивации блоки памяти (объектов), которые больше не доступны.Чтобы лучше проиллюстрировать это, вот некоторые examples.

function foo() {
    var bar = new LargeObject();
    bar.someCall();
}

При foo возвращается, объект которых bar указывает на автоматически доступны для сбора мусора, потому что нет ничего, что имеет ссылку на it.

Сравните это с:

function foo() {
    var bar = new LargeObject();
    bar.someCall();
    return bar;
}

// somewhere else
var b = foo();

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

Closures

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

function sum (x) {
    function sumIt(y) {
        return x + y;
    };
    return sumIt;
}

// Usage
var sumA = sum(4);
var sumB = sumA(3);
console.log(sumB); // Returns 7

Функции объекта, созданного в контексте выполнения звонка на sum can’ т быть мусора, а it’ S, на которые ссылается глобальная переменная и все еще очень доступна.Он все еще может быть выполнен через sumA(n).

Let’ посмотрим на другой пример.Здесь мы можем получить доступ к largeStr?

var a = function () {
    var largeStr = new Array(1000000).join('x');
    return function () {
        return largeStr;
    };
}();

Да, мы можем, через a(), так it’ ы не собираются.Как насчет этого

var a = function () {
    var smallStr = 'x';
    var largeStr = new Array(1000000).join('x');
    return function (n) {
        return smallStr;
    };
}();

Мы can’ т доступ к его больше и it’ SA кандидатом для мусора collection.

Timers

Одно из худших мест утечки в цикле, или в setTimeout() / setInterval(), но это совершенно common.

Рассмотрим следующие example.

var myObj = {
    callMeMaybe: function () {
        var myRef = this;
        var val = setTimeout(function () { 
            console.log('Time is running out!'); 
            myRef.callMeMaybe();
        }, 1000);
    }
};

Если мы затем запустить:

myObj.callMeMaybe();

Начать таймер, мы можем видеть каждый второй “Время на исходе!” Если мы затем запустить:

myObj = null;

Таймер все равно будет срабатывать.myObj won’ т быть мусора, как закрытие прошло на setTimeout должен быть живым, чтобы быть выполнены.В свою очередь, содержит ссылки на myObj, как он захватывает myRef.Это был бы таким же, если we’ D прошло закрытие любой другой функции, сохраняя ссылки на it.

Стоит также помнить, что ссылки внутри setTimeout / setInterval вызовов, таких как функции, необходимо будет выполнить и завершить, прежде чем они могут быть мусора collected.

Быть в курсе производительности Traps

It’ Важно никогда не оптимизировать код, пока вы на самом деле нужно.Это can’ T переоценить.It’ Легко видеть, число микро-тесты показывают, что N является более оптимальным, чем М V8, но протестировать ее в реальных модуль программы или фактического применения, и истинное влияние этих оптимизаций может быть многоболее minimal чем вы были expecting.

Speed trap. Делать слишком много может быть столь же вредны, как ничего не делает.Изображение с сайта:. Тим Sheerman-Chase

Let’ ы говорят, что мы хотим создать модуль, который:

  • Принимает локальный источник данных, содержащих элементы с цифровой ID,
  • Рисует таблицу, содержащую эти данные,
  • Добавляет обработчики событий для переключения классе, когда пользователь нажимает на любую cell.

Есть несколько различных факторов на эту проблему, хотя it’ S достаточно просто решить.Как мы можем хранить данные?Как мы можем эффективно нарисовать таблицу и добавить его в DOM?Как мы можем обрабатывать события на этом столе оптимально

Первый (наивные) взять на себя эту задачу могли бы хранить каждую часть имеющихся данных в объект, который мы группой в массив.Можно использовать JQuery для перебора данных и нарисовать таблицу, а затем добавить его в DOM.Наконец,может использовать привязку события для добавления щелкните поведение, которое мы desire.

Примечание: Это не то, что вы должны быть doing

var moduleA = function () {

    return {

        data: dataArrayObject,

        init: function () {
            this.addTable();
            this.addEvents();
        },

        addTable: function () {

            for (var i = 0; i < rows; i++) {
                $tr = $('<tr></tr>');
                for (var j = 0; j < this.data.length; j++) {
                    $tr.append('<td>' + this.data[j]['id'] + '</td>');
                }
                $tr.appendTo($tbody);
            }

        },
        addEvents: function () {
            $('table td').on('click', function () {
                $(this).toggleClass('active');
            });
        }

    };
}();

Простой, но он получает работу done.

В этом случае, однако, только данные we’ повторной итерации являются идентификаторами, числового имущества, которое может быть проще представлены в стандартном массиве.Интересно, что непосредственно с помощью DocumentFragment и собственные методы DOM являются более оптимальным, чем с помощью JQuery (таким образом) для нашего стола поколения, и, конечно, событие делегации, как правило, более мощные, чем привязка каждого td индивидуально.

Отметим, что делает использование JQuery DocumentFragment внутренне за кулисами, но в нашем примере, код вызова append() внутри цикла, и каждый из этих вызовов имеет мало знают о других так что она не может быть в состоянии оптимизироватьэтому примеру.Это должно надеюсь, не будет болевые точки, но будьте уверены, для сравнения собственный код, чтобы быть sure.

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

var moduleD = function () {

    return {

        data: dataArray,

        init: function () {
            this.addTable();
            this.addEvents();
        },
        addTable: function () {
            var td, tr;
            var frag = document.createDocumentFragment();
            var frag2 = document.createDocumentFragment();

            for (var i = 0; i < rows; i++) {
                tr = document.createElement('tr');
                for (var j = 0; j < this.data.length; j++) {
                    td = document.createElement('td');
                    td.appendChild(document.createTextNode(this.data[j]));

                    frag2.appendChild(td);
                }
                tr.appendChild(frag2);
                frag.appendChild(tr);
            }
            tbody.appendChild(frag);
        },
        addEvents: function () {
            $('table').on('click', 'td', function () {
                $(this).toggleClass('active');
            });
        }

    };

}();

Мы могли бы тогда искать другие способы повышения производительности.Вы, возможно, где-то читал, что с помощью прототипных картина более оптимальным, чем модуль модель (мы это подтвердили wasn’ T ранее), или слышали, что с помощью JavaScript шаблонов рамок высоко оптимизирован.Иногда они есть, но использовать их, поскольку они делают для читаемый код.Кроме того, предварительная компиляция!.Let’ S тест и узнайте, насколько это верно держать в practice.

moduleG = function () {};

moduleG.prototype.data = dataArray;
moduleG.prototype.init = function () {
    this.addTable();
    this.addEvents();
};
moduleG.prototype.addTable = function () {
    var template = _.template($('#template').text());
    var html = template({'data' : this.data});
    $tbody.append(html);
};
moduleG.prototype.addEvents = function () {
   $('table').on('click', 'td', function () {
       $(this).toggleClass('active');
   });
};

var modG = new moduleG();

Как выясняется, в этом случае выигрыш в производительности незначительна. Выбор в пользу шаблонов и prototypes didn’ T действительно предлагают нечто большее, чем то, что мы имели раньше.Тем не менее, производительность isn’ т действительно причина современной разработчикам использовать любой из этих вещей — it’ ы читаемости, модель наследования и ремонтопригодности они приносят в вашу codebase.

Более сложные проблемы включают в себя эффективно рисование изображений с использованием canvas и манипулирования пикселей data с или без типизированных arrays

Всегда давайте микро-тестов близка lookover прежде, чем исследовать их использования в вашем приложении.Некоторые из вас могут вспомнить наличие шаблонов стрелять-off и расширенный перестрелка что followed.Вы хотите, чтобы убедиться, что тесты aren’ T на влияние ограничений you’ повторно вряд ли увидим в реальных приложениях — тест оптимизаций вместе в реальной code.

V8 оптимизации Tips

Пока подробно каждую оптимизации V8 выходит за рамки этойстатьи, есть, конечно, много советов, стоит отметить.Имейте это в виду и you’ будете уменьшить ваши шансы на написание unperformant code.

  • Некоторые модели вызовет V8, чтобы выручить оптимизации.Try-Catch, например, вызовет такой финансовой помощи.Для получения дополнительной информации о том, что функции может и can’ т быть оптимизированы, вы можете использовать --trace-opt file.js с d8 оболочки утилиту, которая поставляется с V8.
  • Если вы заботитесь о скорости, очень сильно постараться, чтобы сохранить ваши функции мономорфно, т. е. убедиться, что переменные (в том числе свойств, массивы и параметры функции) только когда-либо содержать объекты с такой же скрытый класса.Например, don’ т сделать это:
function add(x, y) { 
   return x+y;
} 

add(1, 2); 
add('a','b'); 
add(my_custom_object, undefined);
  • Don’ т нагрузки от неинициализированные или удаленные элементы.Это won’ т сделать разницу в выходные, но это будет делать вещи slower.
  • Don’ T написать огромное функции, так как они являются более трудными optimize

Дополнительные советы, часы Daniel Clifford’ с Google I / O разговоров Нарушение Limit JavaScript скорость с V8 так как она охватывает эти темы хорошо. Оптимизация для V8 — Series Также стоит read.

Объекты Vs.Массивы: Какой я должен использовать

  • Если вы хотите сохранить кучу цифр, или список объектов того же типа, используйте array.
  • Если то, что вам нужно, это семантически объект с кучей свойств (различного типа), используйте объект с свойствами.That’ с довольно эффективным с точки зрения памяти, и it’ S также довольно fast.
  • Integer-индексированных элементов, независимо от того, they’ Re хранятся в массиве или объекте, являются гораздо быстрее перебрать, чем объект properties.
  • Недвижимость на объекты достаточно сложны: они могут быть созданы с сеттеры, и с различными перечислимости и возможность записи.Продукты в массивах aren’ T состоянии быть настроены как тяжело — они либо есть, либо они don’ T.На двигателе уровне, это позволяет более оптимизации с точки зрения организации памяти, представляющий структуру.Это особенно полезно, когда массив содержит цифры.Например, если вам нужно векторов, don’ T определить класс со свойствами X, Y, Z; использовать массив вместо ..

Там на самом деле только одно существенное различие между объектами и массивами в JavaScript, и that’ S arrays’ Магия length собственность.Если вы следить за данную недвижимость самостоятельно, объекты V8 должно быть так же быстро, как arrays.

Советы при использовании Objects

  • Создать объекты с помощью функции конструктора.Это гарантирует, что все объекты, созданные с ней иметь одинаковые скрытые класса и помогает избежать изменения этих классов.В качестве дополнительного преимущества, it’ S также немного быстрее, чем Object.create()
  • Есть никаких ограничений на число различных типов объектов вы можете использовать в вашем приложении или от их сложности (в пределах разумного: длинные цепочки прототипов, как правило, больно, и объекты, имеющие лишь несколько свойств получить специальное представление that’ SA немногобыстрее, чем больше объектов).Для “горячих” объектов, старайтесь держать короткие цепочки прототипов и количество полей в low.

Объект CloningКлонирование объектов является общей проблемой для разработчиков приложений.В то время как it’ с возможным теста, насколько хорошо различные реализации работы с такого рода проблемой в V8, будьте очень осторожны при копировании ничего.Копирование большие вещи, как правило, медленно — don’ т сделать это.for..in петель в JavaScript особенно плохо для этого, так как они имеют дьявольский спецификацией и, вероятно, никогда не будет быстрым в любой двигатель для произвольного objects.

Когда вы абсолютно необходимо скопировать объекты в производительности кода критической пути (и вы can’ T выйти из этой ситуации), использовать массив или обычай “конструктор копирования” функция, которая копирует каждое свойство в явном виде.Это, вероятно, самый быстрый способ сделать это:

function clone(original) {
  this.foo = original.foo;
  this.bar = original.bar;
}
var copy = new clone(original);

кэширования данных функций в модуле PatternКэширование ваших функций при использовании модуля картина может привести к улучшению производительности.См. ниже пример, когда изменение you’ повторно, вероятно, привыкли к тому, медленнее, так как она заставляет новых копий функций-членов должны быть созданы все time.

Также отметим, что при таком подходе может быть значительно более оптимальным, чем просто полагаясь на прототипных картины (как это было подтверждено с помощью теста jsPerf)

Performance improvements Повышение производительности при использовании модуля или прототипных patterns.

Вот испытания прототип шаблона по сравнению с модулем performance

  // Prototypal pattern
Klass1 = function () {}
Klass1.prototype.foo = function () {
log('foo');
}
Klass1.prototype.bar = function () {
log('bar');
}

// Module pattern
Klass2 = function () {
var foo = function () {
log('foo');
},
bar = function () {
log('bar');
};

return {
foo: foo,
bar: bar
}
}

// Module pattern with cached functions
var FooFunction = function () {
log('foo');
};
var BarFunction = function () {
log('bar');
};

Klass3 = function () {
return {
foo: FooFunction,
bar: BarFunction
}
}

// Iteration tests

// Prototypal
var i = 1000,
objs = [];
while (i--) {
var o = new Klass1()
objs.push(new Klass1());
o.bar;
o.foo;
}

// Module pattern ...

Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров

Comments are closed.