Оптимизация JavaScript-кода для движка V8 (от Google)
- Порядок свойств объектов. Всегда инициализируйте свойства объектов в одном и том же порядке. Нужно это для того, чтобы одинаковые объекты использовали одни и те же скрытые классы, и, как следствие, оптимизированный код.
- Динамические свойства. Добавление свойств к объектам после создания экземпляра объекта приведёт к изменению скрытого класса и к замедлению методов, которые были оптимизированы для скрытого класса, используемого объектами ранее. Вместо добавления свойств динамически, назначайте их в конструкторе объекта.
- Методы. Код, который несколько раз вызывает один и тот же метод, будет выполняться быстрее, чем код, который вызывает несколько разных методов по одному разу (из-за встроенных кэшей).
- Массивы:
- Избегайте разреженных массивов, ключи которых не являются последовательными числами. Разреженный массив, то есть массив, некоторые из элементов которого отсутствуют, будет обрабатываться системой как хэш-таблица. Для доступа к элементам такого массива требуется больше вычислительных ресурсов.
- Постарайтесь избежать заблаговременного выделения памяти под большие массивы. Лучше, если их размер будет увеличиваться по мере надобности.
- Не удаляйте элементы в массивах. Из-за этого они превращаются в разреженные массивы.
- Числа. V8 представляет числа и указатели на объекты, используя 32 бита. Он задействует один бит для того, чтобы определить, является ли некое 32-битное значение указателем на объект (флаг — 1), или целым числом (флаг — 0), которое называется маленьким целым числом (SMall Integer, SMI) из-за того, что его длина составляет 31 бит. Если для хранения числового значения требуется более 31 бита, V8 упакует число, превратив его в число двойной точности и создаст новый объект для того, чтобы поместить в него это число. Постарайтесь использовать 31-битные числа со знаком везде, где это возможно, для того, чтобы избежать ресурсоёмких операций упаковки чисел в JS-объекты.
Влияние замыканий на производительность
Без необходимости создавать функции внутри функций в тех случаях, когда замыкания не нужны, не следует. Использование этой техники увеличивает требования к производительности как в части скорости, так и в части потребления памяти.
Например, при написании нового класса есть смысл помещать все методы в прототип его объекта, а не описывать их в тексте конструктора. Если сделать по-другому, то при каждом создании объекта для него будет создан свой экземпляр каждого из методов, вместо того чтобы наследовать их из прототипа.
Пример отсюда
Код без использования преимуществ замыкания:
1 2 3 4 5 6 7 8 9 10 |
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; }; } |
Тот же код с использованием замыканий (методы вынесены в прототип):
1 2 3 4 5 6 7 8 9 10 11 12 |
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype = { getName: function() { return this.name; }, getMessage: function() { return this.message; } }; |
Методы вынесены в прототип. Тем не менее, переопределять прототип — само по себе является плохой привычкой, поэтому давайте перепишем всё так, чтобы новые методы просто добавились к уже существующему прототипу.
1 2 3 4 5 6 7 8 9 10 |
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype.getName = function() { return this.name; }; MyObject.prototype.getMessage = function() { return this.message; }; |
Код выше можно сделать аккуратнее:
1 2 3 4 5 6 7 8 9 10 11 12 |
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } (function() { this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; }; }.call(MyObject.prototype)); |
В обоих примерах выше методы определяются один раз — в прототипе. И все объекты, использующие данный прототип, будут использовать это определение без дополнительного расхода вычислительных ресурсов.