Подтвердить что ты не робот

Достиг ли я пределов размера объектов, которые может обрабатывать JavaScript в моем браузере?

Я встраиваю большой массив в теги <script> в свой HTML, как это (ничего удивительного):

<script>
    var largeArray = [/* lots of stuff in here */];
</script>

В этом конкретном примере массив содержит 210 000 элементов. Это значительно ниже теоретического максимума 2 31 - на 4 порядка. Здесь интересная часть: если я сохраню источник JS для массива в файл, этот файл составляет > 44 мегабайта (точнее, 46 573 399 байт).

Если вы хотите убедиться сами, вы можете загрузить его из GitHub. (Все данные в нем консервированы, поэтому многое из этого повторяется. Это не будет иметь место в производстве.)

Теперь я действительно не забочусь о том, чтобы обслуживать столько данных. Мой сервер gzip его ответы, поэтому на самом деле не так много времени, чтобы получить данные по проводу. Тем не менее, существует очень неприятная тенденция для страницы, после загрузки, в сбой браузера. Я вообще не тестирую IE (это внутренний инструмент). Моими основными целями являются Chrome 8 и Firefox 3.6.

В Firefox я вижу достаточно полезную ошибку в консоли:

Error: script stack space quota is exhausted

В Chrome я просто получаю страницу sad-tab:

enter image description here

Вырезать на погоню, уже

  • Это слишком большие данные для современных современных высокопроизводительных браузеров?
  • Есть ли что-нибудь, что я могу сделать *, чтобы изящно обрабатывать эти данные?

Кстати, я смог заставить это работать (читать: не сбрасывать вкладку) в Chrome. Я действительно думал, что Chrome, по крайней мере, был сделан из более жестких вещей, но, видимо, я ошибся...


Изменить 1

@Crayon: Я не хотел оправдывать, почему я хотел бы отправить эти данные в браузер сразу. Короткая версия: либо я решаю эту (по общему признанию, не очень-легкую) проблему, либо мне приходится решать целый ряд других проблем. На данный момент я предпочитаю более простой подход.

@various: прямо сейчас я не особо ищу способы уменьшить количество элементов в массиве. Я знаю, что могу реализовать пейджинг Ajax или что-то делать, но это создает для меня собственный набор проблем в других отношениях.

@Phrogz: каждый элемент выглядит примерно так:

{dateTime:new Date(1296176400000),
 terminalId:'terminal999',
 'General___BuildVersion':'10.05a_V110119_Beta',
 'SSM___ExtId':26680,
 'MD_CDMA_NETLOADER_NO_BCAST___Valid':'false',
 'MD_CDMA_NETLOADER_NO_BCAST___PngAttempt':0}

@Will: но у меня есть компьютер с 4-ядерным процессором, 6 гигабайт оперативной памяти, более чем половиной терабайта дискового пространства... и я даже не прошу браузер сделать это быстро - я просто просил его работать вообще! ☹


Изменить 2

Миссия выполнена!

С подсказками от Juan, а также Guffa, я смог получить это работать! Казалось бы, проблема заключалась в разборе исходного кода, а не в работе с ним в памяти.

Подводя итог комментарию комментария к ответу Хуана: мне пришлось разделить мой большой массив на несколько меньших, а затем Array#concat() их, но этого было недостаточно. Я также должен был помещать их в отдельные инструкции var. Вот так:

var arr0 = [...];
var arr1 = [...];
var arr2 = [...];
/* ... */
var bigArray = arr0.concat(arr1, arr2, ...);

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


*, кроме очевидного: отправка меньше данных в браузер

4b9b3361

Ответ 1

Вот что я хотел бы попробовать: вы сказали, что это файл размером 44 МБ. Это, безусловно, занимает более 44 МБ памяти, я предполагаю, что это занимает намного больше 44 МБ ОЗУ, возможно, половину концерта. Не могли бы вы просто сократить данные до тех пор, пока браузер не выйдет из строя и не увидит, сколько памяти использует браузер?

Даже приложения, которые запускаются только на сервере, будут хорошо обслуживать, чтобы не читать 44 МБ файл и хранить его в памяти. Сказав все это, я считаю, что браузер должен иметь возможность справиться с этим, поэтому позвольте мне запустить несколько тестов.

(с использованием Windows 7, 4 ГБ памяти)

Первый тест Я разрезал массив пополам и проблем не было, использует 80 МБ, без сбоев

Второй тест Я разделил массив на два отдельных массива, но все еще содержит все данные, использует 160 Мб, без сбоев

Третий тест Поскольку Firefox сказал, что у него закончилось стека, проблема в том, что он не может разобрать массив сразу. Я создал два отдельных массива, arr1, arr2, затем arr3 = arr1.concat(arr2); Он работал нормально и использует лишь немного больше памяти, около 165 МБ.

Четвертый тест Я создаю 7 из этих массивов (по 22 МБ каждый) и контактирую их, чтобы проверить пределы браузера. Для завершения загрузки страницы требуется около 10 секунд. Объем памяти достигает 1,3 ГБ, а затем он возвращается до 500 МБ. Так что хром может справиться с этим. Он просто не может разобрать его все сразу, потому что он использует какую-то рекурсию, о чем можно узнать в сообщении об ошибке консоли.

Отвечать. Создавайте отдельные массивы (менее 20 МБ каждый), а затем объединяйте их. Каждый массив должен быть в своем собственном выражении var, а не делать несколько объявлений с одним var.

Я бы по-прежнему рассматривал выборку только необходимой части, это может сделать браузер вялым. однако, если это внутренняя задача, это должно быть хорошо.

Последняя точка: вы не на максимальных уровнях памяти, а только на максимальных уровнях синтаксического анализа.

Ответ 2

Да, это слишком много, чтобы спросить обозревателя.

Этот объем данных будет управляться, если он уже был данными, но это еще не данные. Учтите, что браузер должен разбирать этот огромный блок исходного кода, проверяя, что синтаксис складывается для всего этого. После анализа в действительный код, код должен выполняться для создания фактического массива.

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

Разделение данных на несколько меньших массивов, возможно, упростит браузер.

Ответ 3

Вам действительно нужны все данные? вы не можете передавать только данные, необходимые в настоящее время с помощью AJAX? Подобно Google Maps - вы не можете вместить все данные карты в память браузера, они отображают только ту часть, которую вы сейчас видите.

Помните, что 40 мегабайт жестких данных можно раздуть гораздо больше во внутреннем представлении браузера. Например, интерпретатор JS может использовать хэш-таблицу для реализации массива, что добавит дополнительные служебные данные памяти. Кроме того, я ожидаю, что в браузерах хранятся как исходный код, так и JS-память, что само по себе удваивает объем данных.

JS предназначен для обеспечения взаимодействия клиентского интерфейса на стороне клиента, а не для обработки нагрузок данных.

EDIT:

Кстати, вы действительно думаете, что пользователям понравится загрузка 40 мегабайт кода? Есть еще много пользователей с менее широкополосным доступом в Интернет. Выполнение script будет приостановлено до тех пор, пока не будут загружены все данные.

EDIT2:

Я просмотрел данные. Этот массив определенно будет представлен как хэш-таблица. Также многие объекты являются объектами, для которых требуется отслеживание ссылок... это дополнительная память.

Я предполагаю, что производительность будет лучше, если бы это был простой вектор примитивных данных.

EDIT3: данные, безусловно, могут быть упрощены. Основная его часть - это повторяющиеся строки, которые могут быть закодированы в некотором роде как целые числа или что-то в этом роде. Кроме того, у моей Opera проблемы с отображением текста, не говоря уже о его интерпретации.

EDIT4: Забудьте объекты DateTime! Используйте временные метки или строки эпохи unix, но не объекты!

EDIT5: ваш процессор не имеет значения, поскольку JS является однопоточным. И ваша оперативная память тоже не имеет значения, большинство браузеров 32bit, поэтому они не могут использовать большую часть этой памяти.

EDIT6: Попробуйте изменить индексы массива на последовательные целые числа (0, 1, 2, 3...). Это может заставить браузер использовать более эффективную структуру данных массива. Вы можете использовать константы для эффективного доступа к элементам массива. Это уменьшит размер массива огромным куском.

Ответ 4

Попробуйте получить данные с помощью Ajax в качестве страницы JSON. Я не знаю точного размера, но в Google Chrome мне удалось собрать большие объемы данных.

Ответ 5

Используйте ленивую загрузку. Имеют указатели на данные и получают их, когда пользователь спрашивает.

Этот метод используется в разных местах для управления миллионами записей данных.

[изменить]

Я нашел то, что искал. Виртуальная прокрутка в jqgrid. Это 500k записей ленивый загружен.

Ответ 6

Я бы попробовал использовать его как одну большую строку с разделителем между каждым "элементом", а затем использовать split, что-то вроде:

var largeString = "item1,item2,.......";
var largeArray = largeString.split(",");

Надеемся, что строка не выдохнет так быстро.

Изменить: чтобы проверить его, я создал фиктивный массив с 200 000 простых элементов (каждый номер одного номера), и Chrome загрузил его в одно мгновение. 2 000 000 предметов? Пара секунд, но не крушение. 6 000 000 элементов массива (файл размером 50 МБ) сделали загрузку Chrome примерно на 10 секунд, но все равно, никаких сбоев в любом случае.

Итак, это заставляет меня думать, что проблема заключается не в самом массиве, а в его содержании. Оптимизируйте содержимое на простые элементы, затем проанализируйте их "на лету" и он должен работать.