Примечание переводчика: я впервые перевел иностранный язык, и мои слова неизбежно немного неясны, но я старался изо всех сил выразить оригинальное намерение автора и не имел большого польского. Критика и исправление приветствуются. Кроме того, эта статья длинная и имеет большое количество информации, которая может быть трудно переварить. Пожалуйста, оставьте сообщение, чтобы обсудить детали. Эта статья в основном фокусируется на оптимизации производительности V8, и некоторые из контента не применимы ко всем двигателям JS. Наконец, укажите источник при перепечатку :)
============================================================================
Многие двигатели JavaScript, такие как двигатель Google V8 (используемый Chrome и Node), разработаны специально для больших приложений JavaScript, которые требуют быстрого выполнения. Если вы разработчик и обеспокоены использованием памяти и производительности страницы, вы должны понять, как работает двигатель JavaScript в вашем браузере. Будь то V8, Spidermonkey (Firefox) Carakan (Opera), чакра (IE) или другие двигатели, это может помочь вам лучше оптимизировать ваше приложение . Это не означает, что вы должны оптимизировать специально для определенного браузера или двигателя, и никогда не делать этого.
Тем не менее, вы должны задать себе несколько вопросов:
Сайт быстрого загрузки похож на быстрого спортивного автомобиля, который требует специально индивидуальных деталей. Источник изображения: dhybridcars.
При написании высокопроизводительного кода есть некоторые общие ловушки, и в этой статье мы покажем некоторые проверенные и лучшие способы написать код.
Если у вас нет глубокого понимания двигателей JS, нет проблем с разработкой большого веб -приложения, точно так же, как человек, который может водить, видел только капюшон, но не двигатель внутри капюшона. Учитывая, что Chrome - первый выбор моего браузера, давайте поговорим о его двигателе JavaScript. V8 состоит из следующих основных частей:
Сбор мусора - это форма управления памятью , которая на самом деле является концепцией коллекционера, пытаясь переработать память, занятую объектами, которые больше не используются. На языке сбора мусора, как JavaScript, объекты, которые все еще ссылаются в приложении, не будут очищены.
Вручную устранение ссылок на объекты в большинстве случаев не требуется. Все будет работать очень хорошо, просто разместив переменные, где они необходимы (в идеале, как можно более локально, то, то есть функция, которую они используют вместо внешнего слоя функции).
Коллекционер мусора пытается переработать память. Источник изображения: Valtteri Mäki.
В JavaScript невозможно принудительно собрать мусор. Вы не должны делать этого, потому что процесс сбора мусора контролируется во время выполнения, и он знает, какое время лучше для очистки.
Есть много обсуждений по переработке памяти JavaScript в Интернете по поводу удаления ключевых слов. Хотя его можно использовать для удаления атрибутов (ключей) в объектах (MAP), некоторые разработчики считают, что они могут использоваться для насилия «размер». Рекомендуется избегать использования удаления по возможности. В приведенном ниже примере delete ox 的弊大于利,因为它改变了o的隐藏类,并使它成为一个"慢对象"。
var o = {x: 1}; Удалить OX; // Истинный Ок; // неопределенныйВы легко найдете удаление ссылки в популярных библиотеках JS - это лингвистически целенаправленно. Здесь следует отметить, что избегает изменения структуры «горячего» объекта во время выполнения. Двигатель JavaScript может обнаружить такие «горячие» объекты и попытаться оптимизировать их. Если структура объекта существенно не изменяется в течение жизненного цикла, двигатель будет проще для его оптимизации объекта, а операция удаления фактически вызовет это большие структурные изменения, что не способствует оптимизации двигателя.
Есть также недоразумения о том, как работает NULL. Установка ссылки на объект на NULL не делает объект «пустым», он просто устанавливает свою ссылку на пустую. Использование OX = NULL лучше, чем использовать DELETE, но это может не потребоваться.
var o = {x: 1}; o = null; o; // nullo.x // typeerrorЕсли эта ссылка является последней ссылкой на текущий объект, объектом будет собираться мусор. Если эта ссылка не является последней ссылкой на текущий объект, объект доступен и не будет собранным мусором.
Следует также отметить, что глобальные переменные не очищаются коллекционером мусора в течение жизненного цикла страницы. Независимо от того, как долго страница открыта, переменные в области глобального объекта всегда будут существовать, когда запускается JavaScript.
var myglobalnamespace = {};Глобальные объекты будут очищены только при обновлении страницы, перемещаются на другую страницу, закрывают вкладку или выйдя из браузера. Переменные в области функции будут очищены, когда они находятся вне сферы действия, то есть, когда функция выходит, нет никаких ссылок, и такие переменные будут очищены.
Чтобы сборщик мусора собирал как можно больше объектов, не удерживайте объекты, которые больше не используются . Вот несколько вещей, которые нужно помнить:
Далее, давайте поговорим о функциях. Как мы уже говорили, сборы мусора работают путем переработки блоков памяти (объектов), которые больше не доступны. Чтобы проиллюстрировать это лучше, вот несколько примеров.
function foo () {var bar = new bigobject (); bar.somecall ();}Когда FOO возвращается, объект, на который указан с помощью бара, будет автоматически переработан коллекционером мусора, поскольку у него нет существующих ссылок.
Сравнивать:
function foo () {var bar = new bigobject (); bar.somecall (); вернуть полосу;} // где -то elsevar b = foo ();Теперь у нас есть ссылка, указывающая на объект стержня, так что жизненный цикл объекта Bar продолжается от вызова к Foo, пока вызывающий абонент не указал другую переменную B (или B не исходит из области).
Когда вы видите функцию, верните внутреннюю функцию, которая выйдет из доступа к объему, даже после выполнения внешней функции. Это основное закрытие - выражение переменных, которое можно установить в определенном контексте. Например:
Функция sum (x) {function sumit (y) {return x + y; }; return sumit;} // usagevar suma = sum (4); var sumb = suma (3); console.log (sumb); // возвращает 7Функциональный объект (SUMIT), сгенерированный в контексте вызова суммирования, не может быть переработан. На него ссылается глобальная переменная (SUMA) и может быть вызвана через SUMA (n).
Давайте посмотрим на другой пример, где мы можем получить доступ к переменной
var a = function () {var lestr = new Array (1000000) .join ('x'); return function () {return lastgestr; };} ();Да, мы можем получить доступ к самым большим через a (), так что он не переработан. А как насчет следующего?
var a = function () {var smallstr = 'x'; var shargestr = новый массив (1000000) .join ('x'); вернуть функцию (n) {return smallstr; };} ();Мы больше не можем получить доступ к самым большим, это уже кандидат в сборку мусора. [Примечание переводчика: потому что у самогоценного больше нет внешних ссылок]
Одно из худших мест для протекания памяти находится в цикле или в SetTimeout ()/setInterval (), но это довольно распространено. Подумайте о следующих примерах:
var myObj = {callmemaybe: function () {var myRef = this; var val = settimeout (function () {console.log ('время истекает!'); myref.callmemaybe ();}, 1000); }}; Если мы запустим myobj.callmemaybe (); Чтобы запустить таймер, мы видим, что консоль печатает «Время истекает!» каждую секунду. Если myObj = null,定时器依旧处于激活状态。为了能够持续执行,闭包将myObj传递给setTimeout,这样myObj是无法被回收的。相反,它引用到myObj的因为它捕获了myRef。这跟我们为了保持引用将闭包传给其他的函数是一样的。
Стоит также помнить, что ссылки на вызовах SetTimeout/SetInterval (например, функции) должны быть выполнены и завершены, прежде чем они смогут собрать мусор.
Никогда не оптимизируйте код, пока он вам не понадобится. Теперь вы часто можете увидеть некоторые тесты, которые показывают, что N более оптимизирован в V8, чем M, но если вы тестируете его в коде или приложении модуля, вы обнаружите, что эти оптимизации действительно намного меньше, чем вы ожидаете.
Лучше ничего не делать, чем сделать это слишком много. Источник изображения: Тим Шерман-Чейз.
Например, мы хотим создать такой модуль:
В этой проблеме есть несколько разных факторов, хотя ее также легко решить. Как мы храним данные, как мы эффективно рисовать таблицы и добавлять их в DOM, и как мы лучше справляемся с таблицами?
Первоначальный (наивный) подход к решению этих проблем состоит в том, чтобы использовать объекты для хранения данных и поместить их в массив, использовать jQuery, чтобы пройти данные, чтобы нарисовать таблицу и добавить их в DOM, и, наконец, использовать привязку событий с поведением клика, которое мы ожидаем.
Примечание: это не то, что вы должны делать
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 () {$ ('Таблица td'). On ('click', function () {$ (this) .toggleclass ('active');}); }};} ();Этот код просто и эффективно выполняет задачу.
Но в этом случае данные, которые мы проходим, являются лишь цифровым идентификатором свойства, который должен был просто храниться в массиве. Интересно, что лучше использовать DocumentFragment и локальные методы DOM непосредственно, чем генерировать таблицы с использованием jQuery (таким образом), и, конечно, прокси -сервер Event обладает более высокой производительностью, чем связывание каждого TD.
Обратите внимание, что, хотя jQuery использует DocumentFragment внутри, в нашем примере, кодовые вызовы добавляют в цикл, и эти вызовы включают некоторые другие небольшие знания, поэтому эффект оптимизации здесь не очень хорош. Надеемся, что это не будет болезненной точкой, но обязательно сделайте эталон, чтобы убедиться, что ваш код в порядке.
Для нашего примера вышеуказанные практики приносят (желательно) улучшения производительности. Прокси события - это улучшение простого привязки, а дополнительное документирование также помогает.
var moduled = function () {return {data: dataarray, init: function () {this.addtable (); this.addevents (); }, addTable: function () {var td, tr; var fragment = document.createdocumentfragment (); var fragment2 = document.createdocumentfragment (); for (var i = 0; i <rous; 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');}); }};} ();Давайте посмотрим на другие способы повышения производительности. Возможно, вы прочитали, что использование режима прототипа лучше, чем режим модуля, или вы слышали, что использование шаблонов JS работает лучше. Иногда это правда, но они используются, чтобы сделать код более читабельным. Кстати, есть предварительный комплемент! Посмотрим, как это работает на практике?
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 () {$ ('таблица').Оказывается, что улучшения производительности, внесенные в эту ситуацию, незначительны. Выбор шаблонов и прототипов на самом деле больше ничего не предлагает. То есть производительность не является причиной того, что разработчики используют их, и модель читаемости, наследования и обслуживаемость, представленная в коде, являются реальными причинами.
Более сложные проблемы включают эффективное рисование изображений на холсте и манипулирование данными пикселей с массивами типов или без них.
Прежде чем использовать некоторые методы для вашего собственного приложения, обязательно узнайте больше о сравнительном анализе этих решений. Может быть, кто-то все еще помнит, что отстрели и последующие расширения шаблона JS. Вы должны выяснить, что сравнительный анализ не существует в виртуальных приложениях, которые вы не можете видеть, но должны проверить оптимизации, вызванные вашим фактическим кодом.
Точки оптимизации каждого двигателя V8 подробно вводятся вне объема этой статьи. Конечно, здесь стоит упомянуть много советов. Помните эти советы, и вы можете уменьшить код, который имеет низкую производительность.
функция добавить (x, y) {return x+y;} add (1, 2); добавить ('a', 'b'); Добавить (my_custom_object, не определен);Для получения дополнительного контента, пожалуйста, посмотрите обмен Дэниелом Клиффордом в Google I/O. Разбивая ограничение скорости JavaScript с V8. Оптимизация для V8 - серия также очень стоит прочитать.
Существует только одно основное различие между объектами и массивами в JavaScript, то есть свойство магической длины массивов. Если вы сохраняете это свойство самостоятельно, то объекты и массивы в V8 так же быстро, как и в массивах.
Клонирование объекта является общей проблемой для разработчиков приложений. Хотя различные тесты могут доказать, что V8 хорошо справляется с этой проблемой, будьте осторожны. Копирование больших вещей, как правило, медленнее - не делайте этого. Для ... в цикле в JS особенно плох, потому что он имеет демоническую спецификацию и может никогда не быть быстрее, чем любой объект в любом двигателе.
Если вы обязательно скопируете объекты в пути критического кода производительности, используйте массив или пользовательскую функцию «Copy Constructor» для явного копирования каждого свойства. Это, наверное, самый быстрый способ:
Функция клона (оригинал) {this.foo = original.foo; this.bar = original.bar;} var copy = new Clone (Original);Функции кэширования при использовании режима модуля могут привести к улучшению производительности. См. Пример ниже, потому что он всегда создает новую копию функции участника, изменения, которые вы видите, могут быть медленными.
Также обратите внимание, что использование этого метода, очевидно, лучше, а не просто полагаясь на режим прототипа (подтверждено тестом JSPERF).
Улучшения производительности при использовании режима модуля или режима прототипа
Это тест сравнения производительности режима прототипа и режима модуля:
// Прототип шаблона klass1 = function () {} klass1.prototype.foo = function () {log ('foo'); } Klass1.prototype.bar = function () {log ('bar'); } // шаблон модуля klass2 = function () {var foo = function () {log ('foo'); }, bar = function () {log ('bar'); }; return {foo: foo, bar: bar}} // шаблон модуля с кэшированными функциями var foofunction = function () {log ('foo'); }; var barfunction = function () {log ('bar'); }; Klass3 = function () {return {foo: foofunction, bar: barfunction}} // итерационные тесты // Прототипические var i = 1000, objs = []; while (i--) {var o = new klass1 () objs.push (new klass1 ()); О.Бар; o.foo; } // шаблон модуля var i = 1000, objs = []; while (i--) {var o = new klass1 () objs.push (new klass1 ()); О.Бар; o.foo; } // шаблон модуля var i = 1000, objs = []; while (i--) {var o = klass2 () objs.push (klass2 ()); О.Бар; o.foo; } // шаблон модуля с кэшированными функциями var i = 1000, objs = []; while (i--) {var o = klass3 () objs.push (klass3 ()); О.Бар; o.foo; } // См. Тест для получения полной информацииЗатем давайте поговорим о методах, связанных с массивами. В общем, не удаляйте элементы массива , что сделает массив переход к более медленному внутреннему представлению. Когда индекс станет редким, V8 превратит элемент в более медленный словарь.
Массивные литералы очень полезны, и это может намекнуть на размер и тип массива VM. Обычно используется в массивах с небольшими размерами.
// Здесь v8 может видеть, что вам нужен массив с 4 элементами, содержащий числа: var a = [1, 2, 3, 4]; // Не делайте этого: a = []; // здесь V8 ничего не знает о Arrayfor (var i = 1; i <= 4; i ++) {a.push (i);}Это ни в коем случае не является хорошей идеей хранения данных смешанных типов (таких как числа, строки, неопределенные, истинные/ложные) в массиве. Например, var arr = [1, «1», неопределенное, верно, «true»]
Тестирование производительности типового вывода
Как мы видели, массивы целых чисел самые быстрые.
Когда вы используете разреженные массивы, будьте осторожны с элементами доступа, будет намного медленнее, чем полные массивы. Потому что V8 не будет выделять целый кусок места на массив, который использует только часть пространства. Вместо этого он управляется в словаре, экономя оба пространства, но требует времени для доступа.
Тестирование редких массивов и полных массивов
Не предварительно выделяйте большие массивы (такие как элементы более 64 тыс.), Их максимальный размер, но должны быть динамически распределены. Перед тестированием нашей производительности в этой статье помните, что это относится только к некоторым двигателям JavaScript.
Пустые литералы и предварительно выделенные массивы тестируются в разных браузерах
Nitro (Safari) более полезен для предварительно выделенных массивов. В других двигателях (V8, Spidermonkey) предварительное распределение не эффективно.
Предварительное тестирование массива
// пустое arrayvar arr = []; for (var i = 0; i <1000000; i ++) {arr [i] = i;} // предварительно выделяемое Arrayvar arr = new Array (1000000); для (var i = 0; i <1000000; i ++) {arr [i] = i;};В мире веб -приложений скорость - это все. Ни один пользователь не хочет использовать приложение таблицы, которое требует секунды для расчета общего количества столбца или для обобщения информации. Это важная причина, по которой вы хотите сжать каждую производительность в своем коде.
Источник изображения: Per Olof Forsberg.
Понимание и улучшение производительности вашего приложения очень полезно, но это также сложно. Мы рекомендуем следующие шаги для решения болезни производительности:
Некоторые из инструментов и методов, рекомендованных ниже, могут помочь вам.
Есть много способов запустить эталон для фрагментов кода JavaScript, чтобы проверить его производительность - общее предположение состоит в том, что эталон просто сравнивает две временные метки. Этот шаблон указывается командой JSPERF и используется в эталонном наборе SunSpider и Kraken:
var totaltime, start = новая дата, итерации = 1000; while (iterations--) {// фрагмент кода идет здесь} // totaltime → количество полученных миллионов секунд // для выполнения фрагмента кода 1000 timeStotaltime = new Date-Start;Здесь тестируется код, который будет проведен в цикле и запускает установленное количество раз (например, 6 раз). После этого дата начала вычитается с даты окончания, и получено время для выполнения операции в цикле.
Тем не менее, этот анализ делает вещи, которые слишком просты, особенно если вы хотите запустить тесты в нескольких браузерах и средах. Сам сборщик мусора оказывает определенное влияние на результаты. Даже если вы используете решение, такое как Window.ferformance, эти недостатки должны быть приняты во внимание.
Независимо от того, запускаете ли вы только эталонную часть кода, напишите набор для тестирования или кодируйте тест -библиотеку, тесты JavaScript на самом деле больше, чем вы думаете. Для получения более подробных руководящих тестов, я настоятельно рекомендую вам прочитать тесты JavaScript, предоставленные Матиасом Байненс и Джоном Дэвидом Далтоном.
Инструменты разработчика Chrome имеют хорошую поддержку для JavaScript Analytics. Вы можете использовать эту функцию, чтобы обнаружить, какие функции занимают большую часть времени, чтобы вы могли оптимизировать их. Это важно, даже небольшие изменения в коде могут оказать существенное влияние на общую производительность.
Панель анализа инструментов разработчика Chrome
Процесс анализа начинает получать базовую линию производительности кода, а затем проявляет его в виде графиков. Это скажет нам, сколько времени займет код для запуска. Вкладка «Профили» дает нам лучший взгляд на то, что происходит в приложении. Файлы анализа ЦП JavaScript показывают, сколько времени процессора используется в нашем коде, файлы анализа селектора CSS показывают, сколько времени тратится на селекторы обработки, а снимки кучи показывают, сколько памяти используется в наших объектах.
С помощью этих инструментов мы можем разделить, регулировать и повторно рассказать, чтобы измерить, фактически эффективны наши функциональные или оперативные производительности.
Вкладка «Профиль» отображает информацию о производительности кода.
Хорошее введение в анализ, прочитайте профилирование JavaScript Zack Grossbart с помощью инструментов разработчика Chrome.
Совет: В идеале, если вы хотите убедиться, что ваш анализ не зависит от каких-либо установленных приложений или расширений, вы можете использовать флаг --user-data-dir <empty_directory> для запуска хрома. В большинстве случаев этот тест оптимизации метода должен быть достаточным, но для вас также требуется больше времени. Это то, чем может помочь логотип V8.
Внутри Google инструменты разработчика Chrome широко используются такими командами, как Gmail, чтобы помочь обнаружить и устранить утечки памяти.
Статистика памяти в инструментах разработчика Chrome
Память считает частное использование памяти, размер кучи JavaScript, количество узлов DOM, очистка хранения, счетчики прослушивания событий и коллекционеров мусора, которые обеспокоена нашей командой. Рекомендуется чтение технологии Loreena Lee "3 Snapshot". Ключевой момент этого метода состоит в том, чтобы зарегистрировать какое -то поведение в вашем приложении, сбора сбора мусора, проверьте, было ли количество узлов DOM восстановлено в ожидаемой базовой линии, а затем проанализируйте снимки трех кучей, чтобы определить, есть ли утечка памяти.
Управление памятью приложений для одной страницы (например, AngularJS, BACKBONE, EMBER) очень важно, они почти никогда не обновляют страницу. Это означает, что утечки памяти могут быть совершенно очевидны. Одностраничные приложения на мобильных терминалах полны ловушек, потому что устройство имеет ограниченную память и запускает такие приложения, как почтовые клиенты или социальные сети в течение длительного времени. Чем больше способность, тем тяжелее ответственность.
Есть много способов решить эту проблему. В основе, обязательно используйте Dispose () для обработки старых представлений и ссылок (в настоящее время доступны в Backbone (Edge). Эта функция добавлена недавно, сняв обработчик, добавленный в объект «события» представления, и слушатель событий через модель или сбор третьего параметра (Callback Context), переданный к визу. Dispose () также будет вызвана Emerection, в том, что он будет работать. Слушатель, чтобы избежать утечек памяти, когда они обнаруживают, что элементы удаляются.
Некоторый мудрый совет от Дерика Бейли:
Вместо того, чтобы понять, как работают события и ссылки, следуйте стандартным правилам для управления памятью в JavaScript. Если вы хотите загрузить данные в коллекцию костей, полную пользовательских объектов, вы хотите очистить коллекцию, чтобы она больше не занимала память, то требуются все ссылки на коллекцию и ссылки на объекты в коллекции. После того, как используемая ссылка ясна, ресурс перерабатывается. Это стандартные правила сбора мусора JavaScript.
В статье Дерик охватывает много общих недостатков памяти при использовании Backbone.js и как решить эти проблемы.
Учебное пособие по отладке утечек памяти в узле от Felix Geisendörfer также стоит прочитать, особенно когда он является частью более широкого стека SPA.
Когда браузер повторно используют элементы в документе, их необходимо пересматривать, а их позиции и геометрия, которые мы называем рефтовами. Рефтоу блокируют операции пользователей в браузере, поэтому очень полезно понять, что улучшение времени рефта улучшается.
Схема срока повторения
Вы должны запустить рефтовы или перерисовать партиями, но использовать эти методы в меру. Также важно стараться не иметь дело с DOM. Вы можете использовать DocumentFragment, легкий объект документа. Вы можете использовать его как способ извлечь часть дерева документов или создать новый документ «Фрагмент». Вместо постоянного добавления узлов DOM лучше выполнять операции вставки DOM только один раз после использования фрагмента документа, чтобы избежать чрезмерного рефта.
Например, мы пишем функцию, чтобы добавить 20 DOV в элемент. Если вы просто добавляете Div в элемент каждый раз, это запустит 20 реждений.
функция addDivs (element) {var div; for (var i = 0; i <20; i ++) {div = document.createElement ('div'); div.innerhtml = 'hya!'; element.appendchild (div); }}Чтобы решить эту проблему, мы можем использовать DocumentFragment, мы можем добавить в нее новый Div за раз. Добавление документов в DOM после завершения запустит только один раз.
функция addDivs (element) {var div; // Создает новый пустой документ. var fragment = document.createdocumentfragment (); for (var i = 0; i <20; i ++) {div = document.createElement ('a'); div.innerhtml = 'hya!'; fragment.appendchild (div); } element.AppendChild (фрагмент);}См. Сделайте веб -сайт быстрее, оптимизация памяти JavaScript и поиск утечек памяти.
Чтобы помочь обнаружить утечки памяти Javascript, разработчики Google (Marja Hölttä и Jochen Eisinger) разработали инструмент, который работает в сочетании с инструментами разработчика Chrome для получения снимков кучи и обнаружения того, какие объекты вызывают утечку памяти.
Инструмент обнаружения утечки с памятью JavaScript
Есть полная статья о том, как использовать этот инструмент. Рекомендуется перейти на страницу проекта детектора утечки памяти для себя.
Если вы хотите знать, почему такие инструменты не были интегрированы в наши инструменты разработки, есть две причины. Первоначально он был разработан, чтобы помочь нам в разработке конкретных сценариев памяти в библиотеке закрытия, которые более подходят в качестве внешнего инструмента.
Chrome поддерживает передачу некоторых флагов непосредственно в V8 для более подробных результатов выходной оптимизации двигателя. Например, это может отслеживать оптимизацию V8:
"/Приложения/Google Chrome/Google Chrome"-JS-Flags = "-Trace-Opt-trace-deopt"
Пользователи Windows могут запускать Chrome.exe JS-Flags = "Trace-Opt Trace-Deopt"
При разработке приложения можно использовать логотип V8.
Сценарий обработки V8 использует * (asterisk) для идентификации оптимизированных функций и использует ~ (волнистые) для представления нептимизированных функций.
Если вы заинтересованы в том, чтобы узнать больше о логотипе V8 и о том, как работает интерьер V8, настоятельно рекомендуется прочитать отличный пост Вячеслава Эгорова на внутренних интервалах V8.
Высокая точность времени (HRT)-это индивидуальный интерфейс высокого уровня субмиллизации, который не оказывает влияния на системное время и настройки пользователя. Его можно рассматривать как более точный метод измерения, чем новая дата и дата. Это очень помогает нам в написании тестов.
Высокое время (HRT) обеспечивает точную точность времени субмиллисекунды
В настоящее время HRT используется в Chrome (стабильная версия) в windows.performance.webkitnow (), но префикс отбрасывается в Chrome Canary, что позволяет вызову через Window.performance.now (). Пол Ирриш разместил больше о HRT в HTML5Rocks.
Теперь, когда мы знаем текущее точное время, есть ли API, который может точно измерить производительность страницы? Well, now there is a Navigation Timing API that provides an easy way to get accurate and detailed time measurement records when web pages are loaded and presented to users. You can use window.performance.timing in console to get time information:
显示在控制台中的时间信息
我们可以从上面的数据获取很多有用的信息,例如网络延时为responseEnd fetchStart,页面加载时间为loadEventEnd responseEnd,处理导航和页面加载的时间为loadEventEnd navigationStart。
正如你所看到的,perfomance.memory的属性也能显示JavaScript的内存数据使用情况,如总的堆大小。
更多Navigation Timing API的细节,阅读Sam Dutton的Measuring Page Load Speed With Navigation Timing。
Chrome中的about:tracing提供了浏览器的性能视图,记录了Chrome的所有线程、tab页和进程。
About:Tracing提供了浏览器的性能视图
这个工具的真正用处是允许你捕获Chrome的运行数据,这样你就可以适当地调整JavaScript执行,或优化资源加载。
Lilli Thompson有一篇写给游戏开发者的使用about:tracing分析WebGL游戏的文章,同时也适合JavaScript的开发者。
在Chrome的导航栏里可以输入about:memory,同样十分实用,可以获得每个tab页的内存使用情况,对定位内存泄漏很有帮助。
我们看到, JavaScript的世界中有很多隐藏的陷阱,且并没有提升性能的银弹。只有把一些优化方案综合使用到(现实世界)测试环境,才能获得最大的性能收益。即便如此,了解引擎是如何解释和优化代码,可以帮助你调整应用程序。
测量,理解,修复。不断重复这个过程。
图片来源: Sally Hunter
谨记关注优化,但为了便利可以舍弃一些很小的优化。例如,有些开发者选择.forEach和Object.keys代替for和for..in循环,尽管这会更慢但使用更方便。要保证清醒的头脑,知道什么优化是需要的,什么优化是不需要的。
同时注意,虽然JavaScript引擎越来越快,但下一个真正的瓶颈是DOM。回流和重绘的减少也是重要的,所以必要时再去动DOM。还有就是要关注网络,HTTP请求是珍贵的,特别是移动终端上,因此要使用HTTP的缓存去减少资源的加载。
Remembering these points can ensure that you have obtained most of the information in this article. Я надеюсь, что это будет полезно для вас!
原文:http://coding.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/
作者:Addy Osmani