Оптимизация производительности JavaScript и Ajax Введение На завре становения Web повышение эффективности работы Web-страницы обычно означало отказ от использования ненужной HTML-разметки, сохранение минимального объема кода JavaScript и значительное уменьшение размера изображений, чтобы типичному серферу не приходилось заваривать кофе в ожидании загрузки Web-страницы. В результате достижений в различных областях Web-технологии мы столкнулись с абсолютно новым классом проблем производительности. DSL и широкополосные сети сделали высокоскоростной доступ в Интернет доступным для многих, но и ожидания в отношении времени загрузки и отзывчивости дошли до того, что выполняя какие-либо действия на странице, мы рассчитываем на мгновенный результат. Появление Asynchronous JavaScript and XML (Ajax) позволило разработчикам создавать квазинастольные Web-приложения, которые, чтобы отреагировать на событие, больше не требуют загрузки целой страницы. Преимущества этого очевидны, но теперь рядовой пользователь ожидает столь же оперативного реагирования от любых Web-приложений. В последнее время развитие мобильных Web-технологий бросило новый вызов разработчикам, старающимся удовлетворить ожидания современных пользователей ― на целевом устройстве с меньшим экраном, меньшим источником энергии и более медленным соединением. Главная задача этой статьи ― проинформировать читателя о тех мерах, которые следует принять, чтобы максимально повысить производительность приложений JavaScript и Ajax. Статья содержит рекомендации о том, как лучше всего подойти к написанию любого кода для нового или уже существующего приложения. Вы также узнаете о различных инструментах и методах измерения производительности приложений. Наконец, мы расскажем о методах повышения производительности, которые не требуют внесения изменений в существующий код. Советы и рекомендации по JavaScript- и Ajax-разработке Одна из проблем JavaScript-разработки заключается в том, что большой процент разработчиков и Web-дизайнеров, пишущих на JavaScript, в действительности никогда не изучали собственно JavaScript с азов. Их знание языка, как правило, накоплено за годы добавления фрагментов, найденных в Интернете и выполняющих ту или иную функцию. Они знают, как декларировать переменные, писать условные операторы и выполнять расчеты, но никогда не сидели с полным руководством по языку JavaScript и не изучали его с нуля. Чтобы облегчить себе жизнь, программисты обращаются к разнообразным библиотекам и интегрированным средам разработки (ИСР), таким как JQuery и YUI. В использовании библиотек JavaScript нет ничего плохого (я и сам большой их поклонник), но среди современных разработчиков наблюдается тенденция к тому, чтобы хорошо разбираться в своей любимой ИСР JavaScript, но не в самом JavaScript. Эти разработчики часто используют крайне неэффективные методы программирования, иногда применяя функции ИСР даже там, где простой JavaScript работал бы гораздо быстрее. В этом разделе содержатся некоторые практические рекомендации по JavaScript- и Ajax-разработке, особенно в тех областях, которые разработчики, не специализирующиеся на JavaScript, как правило, упускают из виду. Использование внешних файлов JavaScript Золотое правило для достижения максимальной производительности JavaScript-приложений: везде, где это возможно, использовать внешние файлы JavaScript, вместо включения кода JavaScript непосредственно в файлы HTML. Иначе, мало того, что этот код JavaScript придется дублировать на множестве страниц, он не будет кэшироваться Web-браузером, и с каждой последующей загрузкой страницы будет загружаться заново. Первая загрузка страницы будет выполняться значительно медленнее, так как внешний файл требует передачи на сервер дополнительного HTTP-запроса. Однако в большинстве приложений связанный с этим удар по производительности более чем компенсируется экономией времени при последующих загрузках страницы. Исключением из этого правила является случай, когда большинство посетителей просматривает только одну страницу. Или когда нужно, чтобы первая страница загружалась так же быстро или быстрее, чем последующие – в этих случаях предпочтителен встроенный JavaScript. В своей книге "Быстродействующие Web-сайты" (см. ссылку в разделе Ресурсы) Стив Саундерс выдвигает идею "Загрузки после загрузки" (Post-Onload Download), когда код JavaScript первой страницы встроен собственно в HTML-файл, а внешние файлы JavaScript, необходимые для последующих страниц, загружаются динамически, когда страница полностью загружена. Однако в большинстве случаев достаточно использовать только внешние файлы JavaScript. Когда нужны ИСР и библиотеки JavaScript Я обеими руками за использование ИСР и библиотек JavaScript. Они не только помогают решить многие проблемы кросс-браузерной совместимости, но при правильном использовании могут значительно ускорить разработку Web-приложений. Однако с учетом вышесказанного нужно очень внимательно относиться к использованию этих инструментов, так как большинство из них довольно велики и могут ухудшить производительность приложения. Прежде всего, нужно спросить себя: действительно ли мне нужна ИСР? Мое знакомство с ИСР JavaScript состоялось несколько лет назад, когда в разрабатываемом Web-приложении нужно было использовать Ajax. Вместо того чтобы написать собственную функцию XMLHttpRequest, я решил облегчить себе жизнь и воспользовался ИСР Prototype. В приложении не использовались никакие другие возможности среды, кроме выполнения запросов Ajax и обработки ответов от сервера. К счастью, приложение было относительно невелико и предназначалось для внутреннего пользования, так что вопрос производительности не был критическим, но теперь мне ясно, что более легкое решениее, реализующее только функциональность Ajax, было бы лучше. Последняя версия среды Prototype без минимизации и архивирования занимает 141 KB. Часть кода, относящаяся к моей задаче, составляла, вероятно, менее 2 КБ, так что около 139 KБ кода JavaScript в моем приложении абсолютно не использовались. Это увеличило не только время загрузки приложения из-за размера файла, но и время его выполнения, так как код JavaScript выполнялся в браузере. Короче, современные ИСР и библиотеки JavaScript, такие как Prototype, JQuery, Dojo, MooTools, YUI, ExtJS, и т.п., обеспечивают множество возможностей, которые можно использовать или не использовать. Если используется только минимальный набор функций, возможно, стоит рассмотреть более легкое решение. Например, библиотека YUI позволяет по умолчанию загрузить самую минимальную ИСР, а затем выбирать, какие библиотеки в нее добавлять. Размещение и загрузка сценария Книги по HTML учат размещать теги <script> на странице внутри элемента <head>. Забудьте об этом! Размещение тегов <script> в верхней части HTML-страницы не позволяет обработать страницу до завершения загрузки и выполнения кода JavaScript. Если поместить сценарий внутри тега <head>, то пока он загружается и выполняется, никакая часть тела страницы не будет обработана, и у пользователя сложится впечатление, что страница загружается медленно. Чтобы обеспечить максимальную производительность, код JavaScript нужно поместить внизу страницы, по возможности непосредственно перед тегом </body>. Тогда остальная Web-страница (HTML, CSS, изображения, флэш-контент и т.п.) будет загружена и обработана до загрузки и исполнения сценариев, и с точки зрения пользователя она будет загружаться быстро. Если на Web-странице или в приложении используется много кода JavaScript, размещение всего этого кода в одном файле может привести к длительному ожиданию его загрузки и выполнения. Возможно, имеет смысл разбить код JavaScript на несколько файлов и динамически загружать их по мере необходимости, когда загрузка страницы уже завершена. Библиотека LazyLoad JavaScript обеспечивает динамическую загрузку сценария и заботится о некоторых несоответствиях между браузерами, касающихся сохранения порядка выполнения сценария. Подробнее о библиотеке LazyLoad см. в разделе Ресурсы. Минимизация запросов Ajax Запросы Ajax в корне изменили традиционный подход, позволив JavaScript-разработчикам создавать динамичные интерактивные приложения, мало чем отличающиеся от настольных. Результатом стало повсеместное распространение Ajax-запросов. Иногда легко забыть, что хотя пользователь этого не видит, Ajax-запросы выполняют полный HTTP-запрос, что равносильно регулярной загрузке всей страницы. Поэтому минимизации количества Ajax-запросов следует уделять должное внимание. Примером может служить разбиение результатов поиска на страницы. Я часто встречаю приложения, в которых при первом Ajax-запросе записи результатов поиска вводятся в массив JSON, а второй используется для получения общего количества результатов в базе данных для логики их разбиения на страницы. В листинге 1 и листинге 2 приведены примеры этих двух запросов (с использованием ИСР Prototype). Листинг 1. Первый запрос: получение таблицы записей Code: var url = "get_data.php"; var options = { method: "post", parameters: {"page":1,"rows":5}, onSuccess: firstCallbackFunction, onFailure: firstCallbackFunction } new Ajax.Request(url, options); В листинге 2 показан второй запрос для получения количества записей. Листинг 2. Второй запрос: получение общего количества записей Code: var url = "get_count.php"; var options = { method: "post", parameters: {}, onSuccess: secondCallbackFunction, onFailure: secondCallbackFunction } new Ajax.Request(url, options); В листинге 3 и листинге 4 приведены соответствующие HTTP-ответы в формате JSON. Листинг 3. Первый ответ: массив записей Code: { "records": [ {"id":1,"name":"John","email":"[email protected]"}, {"id":2,"name":"Mary","email":"[email protected]"}, {"id":3,"name":"Tony","email":"[email protected]"}, {"id":4,"name":"Emma","email":"[email protected]"}, {"id":5,"name":"Alan","email":"[email protected]"} ] } В листинге 4 показан второй ответ, сообщающий общее количество записей. Листинг 4. Второй ответ: общее количество записей Code: {"total_records": 95} Разделение этих двух Ajax-запросов – лишняя трата ресурсов, так как их легко объединить в один запрос, который дает ответ, приведенный в листинге 5. Листинг 5. Экономичный ответ: общее количество и массив записей Code: { "total_records": 95, "records": [ {"id":1,"name":"John","email":"[email protected]"}, {"id":2,"name":"Mary","email":"[email protected]"}, {"id":3,"name":"Tony","email":"[email protected]"}, {"id":4,"name":"Emma","email":"[email protected]"}, {"id":5,"name":"Alan","email":"[email protected]"} ] } Это уменьшает не только число HTTP-запросов и ответов, но и число серверных сценариев, которые отвечают на AJAX-запросы. Этот пример ― очень простая демонстрация. Чем сложнее приложение, тем важнее уменьшить количество Ajax-запросов. Использование переменных (правильное) Пытаясь свести к минимуму число строк кода, многие разработчики часто упускают из вида использование переменных, что во многих случаях могло бы значительно ускорить выполнение определенного фрагмента кода. Возьмем, к примеру, следующий код, который применяет к элементу различные стили: Листинг 6. Применение стилей к элементу (неэффективное) Code: document.getElementById("myField").style.backgroundColor = "#CCC"; document.getElementById("myField").style.color = "#FF0000"; document.getElementById("myField").style.fontWeight = "bold"; В каждой из приведенных выше строк браузеру придется искать в DOM элемент с идентификатором myField. Вместо того чтобы делать это три раза, можно присвоить результат document.getElementById("myField") переменной и использовать ее в каждой строке, тем самым повысив эффективность этой операции, как показано в листинге 7. Листинг 7. Применение стилей к элементу (эффективное) Code: var myField = document.getElementById("myField"); myField.style.backgroundColor = "#CCC"; myField.style.color = "#FF0000"; myField.style.fontWeight = "bold"; Другой пример, где переменные часто не используются как должно, это случай с циклами for, в которых просматривается массив. Возьмем пример, показанный в листинге 8. Листинг 8. Перебор массива с помощью цикла for (неэффективный) Code: for(var i=0; i < myArray.length; i++) { //сделать что-то } Этот код крайне неэффективен, так как он вычисляет длину массива myArray на каждом цикле. Если с небольшими массивами это может пройти незаметно, то на объемных массивах последствия будут гораздо более ощутимы. Повысить эффективность этого цикла очень легко, причем без единой дополнительной строки кода (см. листинг 9). Листинг 9. Перебор массива с помощью цикла for (эффективный) Code: for(var i=0, arrayLength=myArray.length; i < arrayLength; i++) { //сделать что-то } В листинге 9 мы перенесли ссылку на myArray.length в раздел инициализации оператора for, присвоив ее переменной. Это произойдет только на первой итерации цикла, что сэкономит драгоценное время выполнения каждой последующей итерации. Работа с DOM Обход и манипулирование DOM в целом может стать тяжким бременем для производительности Web-приложения. Проблема в том, что без взаимодействия с DOM приложение невозможно наделить динамичным, богатым интерфейсом. В частности, проблема манипуляций с DOM состоит в том, что браузер должен многократно перезаливать и перерисовывать (практически, заново обрабатывать) соответствующие элементы экрана. В результате, важно свести к минимуму количество таких переработок в коде. Возьмем пример, приведенный в листинге 7, где к элементу с идентификатором myField применяются три отдельных стиля. Это приводит к трем перезаливкам и перерисовкам, что неэффективно, учитывая незначительность вносимых изменений. Все эти действия можно объединить в одно. В листинге 10 приведен более эффективный пример. Листинг 10. Повышение производительности манипуляций DOM путем объединения изменений Code: var myField = document.getElementById("myField"); myField.style.cssText = "background-color: #CCC; color: #FF0000; font-weight: bold"; Благодаря объединению изменений стиля перезаливка и перерисовка выполняется один раз, что улучшает оперативность и производительность приложения. Этот раздел содержит много рекомендаций по разработке JavaScript и Ajax, которые помогут обеспечить оптимальную производительность приложений. Но это ни в коем случае не исчерпывающий список. В разделе Ресурсы содержатся ссылки на превосходные статьи, учебные пособия и книги с практическими рекомендациями по созданию эффективных сценариев JavaScript.
Измерение производительности Ряд инструментов позволяет проанализировать скорость и время загрузки приложения в Web-браузере. Эти инструменты обычно предоставляют возможность запротоколировать и проанализировать фрагмент кода JavaScript, определив время, необходимое для его выполнения. Они предоставляют также средства для анализа сетевого трафика, порожденного загрузкой страницы с точки зрения количества HTTP-запросов, размера загружаемых статических ресурсов (изображения, внешние таблицы стилей и файлы JavaScript) и т.п. В этом разделе рассказывается о различных инструментах протоколирования и анализа сетевой активности в JavaScript-приложениях. Firebug Firebug - это расширение для браузера Mozilla® Firefox®, предоставляющее в распоряжение Web-разработчиков множество полезных функций. В число этих функций входит консоль JavaScript, обработка и выбор DOM, отладка сценариев, просмотр исходного текста DOM, протоколирование, сетевой анализ и многое другое. Для выполнения протоколирования JavaScript в Firebug нужно открыть вкладку Console и нажать кнопку Profile. Затем вы указываете различные функции JavaScript/Ajax на своей странице, и Firebug измерит продолжительность их работы. Firebug предоставляет также API консоли для взаимодействия с профайлером. На рисунке 1 показан образец отчета, сгенерированного профайлером Firebug. Рисунок 1. Образец отчета профайлера Firebug Чтобы использовать инструменты сетевого анализа Firebug, достаточно открыть вкладку Net. Там будут показаны все HTTP-запросы, код ответа и полученные сообщения, исходный домен, размер файла и хронология загрузки страницы. Можно даже углубиться в запрос и увидеть отправленные HTTP-заголовки, полученный ответ и соответствующую информацию по кэшу для рассматриваемого файла. На рисунке 2 показан пример результатов Firebug по сетевому трафику. Рисунок 2. Пример отчета Firebug Net Safari Web Inspector и Chrome Developer Tools Safari® Web Inspector и Chrome® Developer Tools предоставляют аналогичные возможности, но выглядят гораздо красивее. В браузере Safari откройте Web Inspector, перейдя в меню Develop на панели инструментов (возможно, потребуется включить его в настройках Safari) и выбрав Show Web Inspector. Нажмите на вкладку Profile в верхней части окна инспектора и выберите круглый значок записи в левом нижнем углу, чтобы начать протоколирование. Чтобы остановить протоколирование и создать отчет, нажмите значок еще раз. На рисунке 3 приведен пример такого отчета. Рисунок 3. Пример отчета Safari Web Inspector Чтобы измерить время загрузки и HTTP-запросы своего приложения, нажмите кнопку Resources в верхней части окна Inspector. Затем можно просмотреть график используемых сетевых ресурсов по времени или размеру. Пример красивого экрана результатов приведен на рисунке 4. Рисунок 4. Пример отчета Safari Web Inspector по ресурсам Инструментарий Developer Tools для Google Chrome – тот же, что и для Safari (оба браузера основаны на WebKit), но находится в меню Developer под именем Developer Tools. Internet Explorer Developer Tools Internet Explorer® 8 также содержит комплект Developer Tools. Чтобы открыть окно Developer Tools, нажмите клавишу F12. Среди инструментов Internet Explorer есть набор таких же функций, как в программах типа Firebug, но есть и достойный профайлер для измерения производительности функций JavaScript. В Developer Tools выберите вкладку Profiler и нажмите кнопку Start Profiling, чтобы начать протоколирование приложения. Выполните в своем приложении функции, которые нужно проверить, а затем нажмите Stop Profiling, чтобы создать отчет. Он должен выглядеть как на рисунке 5. Рисунок 5. Пример отчета профайлера Developer Tools из Internet Explorer К сожалению, в Developer Tools из Internet Explorer не входит сетевой анализатор. Чтобы проанализировать сетевой трафик приложения для Internet Explorer, можно воспользоваться инструментом Fiddler, который работает почти с любым приложением, генерирующим HTTP-запросы, в том числе Internet Explorer. Подробнее о Fiddler см. в разделе Ресурсы. Профайлер YUI Профайлер YUI – это инструмент протоколирования кода, написанный на JavaScript. В отличие от инструментов, включенных в Web-браузеры (или расширений для браузера, таких как Firebug), профайлер YUI не является визуальным, и его надо включать в Web-страницу. Преимущество этого подхода заключается в том, что можно проверить только конкретные области приложения (а не просто любые функции, которые оно выполняет). Профайлер YUI позволяет зарегистрировать функции, конструкторы классов и объекты, подлежащие измерению. Можно подготовить отчет по результатам протоколирования или добавить функцию фильтра, который позволяет определить целевые области измерения более детально. Отчет создается в формате JSON, что позволяет легко экспортировать результаты в собственное приложение, где можно составить любые таблицы и графики. Одним из основных преимуществ профайлера YUI является то, что он не привязан ни к какому конкретному браузеру. Он будет работать даже на мобильных устройствах с браузером класса A, таким как браузеры на базе WebKit на устройствах типа Apple® iPhone®, Android® и Nokia® N95. Подробнее о профайлере YUI см. в разделе Ресурсы. YSlow YSlow ― это расширение для Firefox, которое подключается к расширению Firebug и измеряет скорость загрузки и выполнения Web-страницы. Оно дает общую оценку, а также подробный анализ производительности по различным аспектам JavaScript и Web-странице в целом. Я выполнил YSlow на странице, которая делает 91 HTTP-запрос, и получил оценку C. YSlow дал полезный совет: на странице, содержащей 10 внешних сценариев JavaScript, постараться объединить их в один. К другим областям оценки относится добавление заголовков Expires, использование GZIP, помещение JavaScript в нижнюю часть страницы, минимизация JavaScript и CSS, удаление дубликатов кода JavaScript и CSS и многое другое. На рисунке 6 приведен пример результата работы YSlow. Рисунок 6. Простой отчет YSlow Повышение производительности без изменения кода Измеририв производительность своего приложения и определив, что нужно сделать для ее повышения, вы, наверное, уже начали думать о том, как изменить его исходный код. Иногда это действительно необходимо, но есть несколько способов улучшения производительности JavaScript и Ajax без всякого изменения кода приложения. Объединение исходных файлов JavaScript Большое приложение JavaScript часто загружает мгого внешних исходных файлов для выполнения разных функций. Возможно, вы используете ИСР, такую как JQuery, и многочисленные плагины, которые придают JQuery дополнительные возможности. Вероятно также, что ваш собственный JavaScript код разделен на несколько файлов. Хотя этот подход имеет свои преимущества, разделение JavaScript на отдельные файлы оказывает серьезное влияние на производительность. Для каждого внешнего файла JavaScript, который загружается в Web-приложение, выполняется отдельный HTTP-запрос, что существенно увеличивает нагрузку и время выполнения сценария. Чтобы уменьшить количество запросов, настоятельно рекомендуется объединить исходные файлы JavaScript везде, где это возможно. Конечно, если тот или иной плагин требуется только для одной страницы, его не нужно включать в единый файл. Возможно, его следует включить в качестве встроенного сценария, так как он не будет использоваться другими страницами. Вполне возможно также, что вам не удастся объединить абсолютно все файлы в один, но чем меньше HTTP-запросов делает приложение, тем быстрее оно загружается. Минимизация числа исходных файлов JavaScript Руководящие принципы программирования гласят, что нужно придерживаться определенного стиля, и для JavaScript это так же справедливо, как для любого другого языка. Проблема в том, что все пробелы, разрывы строк и комментарии, которые вы добавляете в свой код, увеличивают размер файла сценария и время загрузки приложения. Чтобы уменьшить размеры файлов JavaScript, настоятельно рекомендуется минимизировать файлы, прежде чем помещать их в рабочую среду. Минимизация в основном сводится к удалению лишних битов исходного кода для получения файла меньшего размера. В качестве примера потенциальной экономии: одна только минимизация позволила сократить последнюю версию JQuery на момент написания статьи со 155 KБ до 70,6 KБ. Это почти 55%-я экономия. Конечно, предложить уменьшить исходный код легко, но как это сделать? Ни один здравомыслящий человек не станет минимизировать свой код вручную, но, к счастью, есть ряд инструментов разработки, готовых выполнить эту работу за вас. К числу наиболее популярных относятся JSMin Дугласа Крокфорда, Packer Дина Эдвардса и компрессор, включенный в инструментарий Dojo. Лично мне нравится YUI Compressor компании Yahoo!®. Подробнее см. в разделе Ресурсы. Сжатие исходных файлов JavaScript с помощью GZIP В предыдущем разделе говорилось, что можно минимизировать исходные файлы JavaScript, значительно уменьшив их размер. Сжатие файлов с помощью GZIP позволяет дополнительно уменьшить их размер. Лучший способ сделать это ― указать Web-серверу, что надо сжать файлы JavaScript, прежде чем отправлять их клиенту. Если используется Apache 2 (с mod_deflate), и файлы JavaScript хранятся в том же каталоге, можно просто создать файл .htaccess в том же месте, где находятся файлы JavaScript. В этом файле должно содержаться только: SetOutputFilter DEFLATE. Сжатие файлов JavaScript дает значительную экономию. В предыдущем разделе говорилось, что минимизация исходного кода JQuery привела к сокращению размера файла со 155 KБ до 70,6 KБ (экономия 55%). Если сжать этот минимизированный файл, его размер уменьшится до 24 KБ. Общая экономия составляет почти 85%. Результаты зависят от кода, но экономия может быть весьма значительной. Кэширование исходных файлов JavaScript Важно, чтобы Web-браузер правильно кэшировал контент. Например, если используется Apache (с mod_expires) и нужно, чтобы клиент кэшировал файлы JavaScript на два дня, можно добавить директиву из листинга 11 в файл .htaccess, расположенный в том же месте, где хранятся файлы JavaScript (при условии, что имеется специальный каталог для файлов JavaScript, иначе это придется делать в файле конфигурации Apache). Листинг 11. Директива кэширования файлов JavaScript на два дня Code: ExpiresActive on ExpiresDefault "access plus 2 days" Конечно, при внесении изменений клиенты до конца срока кэширования будут использовать сохраненную версию сценария, вместо обновленной. Но клиент можно заставить получать свежуют версию сценария, добавив строку запроса с номером версии в тег <script>, который загружает этот сценарий. Эта строка не повлияет на код JavaScript, но для браузера это совершенно отдельный файл, и он будет загружать свежую версию. Конечно, важно увеличивать номер версии каждый раз при внесении изменений в файл. В крупных приложениях, чтобы предотвратить проблемы, для автоматизации этого процесса применяют специальный сценарий сборки. Заключение В этой статье говорилось о важности производительности JavaScript и Ajax для современных Web-сайтов и приложений. Мы показали, как некоторые приемы рационального программирования JavaScript улучшают оперативность и время загрузки приложений. Затем вы узнали, как измерить производительность существующего приложения с помощью инструментов протоколирования и сетевого анализа. Наконец, вы научились ускорять работу существующих приложений без модификации исходного кода с помощью нескольких простых, но мощных методов уменьшения размеров файла и количества HTTP-запросов, выдаваемых приложением. 18.07.2012 Джо Леннон, разработчик ПО, Независимый разработчик http://www.ibm.com/developerworks/ru/library/wa-aj-jsajaxperf/
Думаю, что автор ошибается. Массив в JS - не совсем массив, это скорее класс. А length - это не функция, вычисляющая количество элементов массива, а свойство, в котором хранится количество. Значение свойства length автоматически меняется при изменении количества элементов массива, а не вычисляется каждый раз. Не имеет смысла вводить дополнительную переменную в цикле.
Неточность у тебя. Length хранит не количество, а индекс последнего элемента + 1. Code: var arr = []; arr[1000] = true; alert(arr.length);