В логике загрузки данных Discovery.js прогрессбар появляется не сразу — есть задержка в 300ms, чтобы прогрессбар "не мелькал", если загрузка завершается быстрее. Для файлов до 50Mb на моем ноутбуке так и происходит: загрузка заканчивается быстрее 300ms, и прогрессбар просто не появляется. Другими словами, для таких размеров прогрессбар заметить практически невозможно.
Но при тестировании меня не покидало ощущение, что задержка появления прогрессбара длится явно дольше, чем ожидаемые 300ms. При этом эта задержка увеличивается с увеличением размера файла и проявляется только в случаях, когда файл открывается непосредственно в закладке или загружается через сеть. В плейграунде эта задержка не наблюдается. Всё указывало на то, что при загрузке через DOM что-то происходит иначе. Но как я ни пытался это отладить или замерить, разобраться не удалось. И заметил я это уже после релиза JsonDiscovery, когда готовил материалы для будущих постов. Понять, в чём дело, помогла случайность.
Я работал над второй попыткой добавить TransformStream в пайплайн загрузки данных в Discovery.js, чтобы интегрировать DecompressionStream. Добавить такую интеграцию не так сложно, но мне мало просто добавить функциональность — важно, чтобы она работала оптимально. Пока мои эксперименты не дали хороших результатов: стало ясно, что нужно больше времени, чем у меня было, и я отложил работу. Но в процессе пришло понимание, что для эффективности пайплайна стримов нужно балансировать размер чанков (payload size) на каждом узле пайплайна. Если этого не делать, то на определённых узлах скапливается слишком много данных, что приводит к увеличеному потреблению памяти, либо размер чанков требует больше времени на обработку, что приводит к блокировке main thread, и выливается в то, что пайплайн работает рывками. А должно быть так, чтобы каждый узел пайпдлайна занимал пропорциональное время, и данные протекали плавно и с предсказуемой скоростью. Но об этом ещё будут посты, когда удастся со всем разобраться.
Как бы там ни было, я протестировал экспериментальный пайплайн с TransformStream на JsonDiscovery и обнаружил, что тот самый "экзотический" стрим JsonDiscovery, что читает из DOM, поставляет чанки в приложение не самым эффективным образом. Проблем оказалось две.
Первая — размер чанков в DOM часто составляет 64Kb. Это приводит к тому, что возникает большое количество сообщений (чанков), которые проходят через стримы и передаются между процессами. При передаче данных между процессами размер сообщений играет меньшую роль, чем их количество. Другими словами, передать сообщение размером 64Kb или 1Mb между процессами по затратам времени примерно одинаково, а вот передача скажем 100 сообщений или 1000 – может отличаться существенно. Все дело в паузах между сообщениями. Так, чтобы передать 100Mb по 64Kb необходимо около 1600 сообщений. Даже если пауза между сообщениями составляет всего 1ms, это уже потеря около 1.6 секунды. На практике задержки между сообщениями могут быть как меньше, так и больше. Поэтому обычно буферизируют сообщения и отправляют пачками. Так поступил и я, добавив буферизацию чанков до 1Mb при чтении из DOM, что позволило практически вдвое ускорить открытие файлов. Хотя это не было ускорением вычитывания файлов, а ускорение вычитывания контента из DOM, так как время открытия файла сравнялось со временем открытия файла в плейграунде, где контент получается напрямую из файловой системы, минуя DOM.