Spec-Zone.ru › Web APIs

Понятия API потоков

API потоков добавляет очень полезный набор инструментов в веб-платформу, предоставляя объекты, которые позволяют JavaScript программно получать доступ к потокам данных, полученным по сети, и обрабатывать их так, как требуется разработчику. Некоторые понятия и термины, связанные с потоками, могут быть для вас новыми — эта статья объясняет всё необходимое.

Потоки на чтение

Поток на чтение — это источник данных, представленный в JavaScript объектом ReadableStream, который течет из основного источника — это ресурс где-то в сети или на вашем домене, откуда вы хотите получить данные.

Существует два типа основных источников:

  • Источники push постоянно передают данные, когда вы к ним обратились, и вам нужно начать, приостановить или отменить доступ к потоку. Примеры включают потоки видео и TCP/веб-сокеты.
  • Источники pull требуют, чтобы вы явно запрашивали данные у них после подключения. Примеры включают операцию доступа к файлу через запрос fetch().

Блоки данных

Данные читаются последовательно в небольших блоках, называемых блоками данных. Блок данных может быть одним байтом или чем-то большим, например, массивом с типом данных определенного размера. Один поток может содержать блоки данных различных размеров и типов.

Readable streams data flow

Блоки данных, помещенные в поток, называются вставленными в очередь — это означает, что они ожидают в очереди, готовые к чтению. Внутренняя очередь отслеживает блоки данных, которые еще не были прочитаны (см. раздел Внутренние очереди и стратегии очереди ниже).

Читатели, потребители и контроллеры

Блоки данных в потоке читаются читателем — это обрабатывает данные по одному блоку за раз, позволяя вам выполнять любые операции, которые вы хотите выполнить с ним. Читатель плюс другой связанный с ним код обработки называется потребителем.

Также есть конструкция, которую вы будете использовать, называемая контроллером — каждый читатель имеет связанный с ним контроллер, который позволяет вам управлять потоком (например, закрыть его, если нужно).

Блокировка

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

Потоки на чтение и потоки байтов

Обратите внимание, что существует два разных типа потоков на чтение. Помимо обычного потока на чтение есть тип, называемый потоком байтов — это расширенная версия обычного потока для чтения подлежащих источников байтов. По сравнению с обычным потоком на чтение, потоки байтов разрешено читать читателям BYOB (BYOB, «принесите свой буфер»). Такой тип читателя позволяет читать потоки непосредственно в буфер, предоставленный разработчиком, сводя к минимуму копирование. Какой подлежащий поток (и, соответственно, читатель и контроллер) будет использовать ваш код, зависит от того, как поток был создан в первую очередь (см. страницу конструктора ReadableStream()).

Вы можете использовать готовые потоки на чтение с помощью механизмов, таких как Response.body из запроса fetch, или создавать свои потоки с помощью конструктора ReadableStream().

Разветвление

Несмотря на то, что только один читатель может читать поток одновременно, можно разделить поток на две идентичные копии, которые затем могут быть прочитаны двумя отдельными читателями. Это называется разветвлением.

В JavaScript это достигается с помощью метода ReadableStream.tee() — он выводит массив, содержащий две идентичные копии исходного потока на чтение, которые затем могут быть независимо прочитаны двумя отдельными читателями.

Вы можете сделать это, например, в ServiceWorker, если хотите получить ответ от сервера и передать его в браузер, но также передать его в кэш ServiceWorker. Поскольку тело ответа нельзя использовать более одного раза, а поток нельзя читать более чем одному читателю одновременно, вам понадобятся две копии, чтобы это сделать.

Teeing data flow

Потоки на запись

Поток на запись — это место назначения, в которое можно записывать данные, представленные в JavaScript объектом WritableStream. Это абстракция над основным приемником — приемником ввода-вывода более низкого уровня, в который записываются сырые данные.

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

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

Внутренняя очередь отслеживает блоки данных, которые были записаны в поток, но еще не были обработаны основным приемником.

Также есть конструкция, которую вы будете использовать, называемая контроллером — каждый писатель имеет связанный с ним контроллер, который позволяет управлять потоком (например, прервать его, если нужно).

Writable streams data flow

Вы можете использовать потоки на запись, используя конструктор WritableStream(). В настоящее время они имеют очень ограниченную доступность в браузерах.

Цепочки конвейеров

API потоков позволяет передавать потоки друг в друга с помощью структуры, называемой цепочкой конвейеров. Для этого существуют два метода:

  • ReadableStream.pipeThrough() — передает поток через преобразующий поток, потенциально изменяя формат данных по пути. Это можно использовать, например, для кодирования или декодирования кадров видео, сжатия или распаковки данных или иного преобразования данных из одной формы в другую.

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

    TransformStream — это конкретная реализация преобразующего потока, но любой объект, который имеет те же свойства потока на чтение и поток на запись, может быть передан pipeThrough().

  • ReadableStream.pipeTo() — передает в поток на запись, который является конечной точкой цепочки конвейеров.

Начало цепочки конвейеров называется исходным источником, а конец — конечным приемником.

pipe chain diagram

Обратная загрузка

Важным понятием в потоках является обратная загрузка — это процесс, с помощью которого отдельный поток или цепочка конвейеров регулирует скорость чтения/записи. Когда поток в последующей цепочке все еще занят и еще не готов принять новые блоки данных, он отправляет сигнал назад по цепочке, чтобы сообщить предыдущим преобразующим потокам (или исходному источнику) замедлить доставку, чтобы не возникло узкого места.

Чтобы использовать обратную загрузку в ReadableStream, мы можем запросить у контроллера размер блока данных, желаемый потребителем, запросив свойство ReadableStreamDefaultController.desiredSize контроллера. Если он слишком мал, наш ReadableStream может сказать своему основному источнику прекратить отправку данных, и мы применяем обратную загрузку вдоль цепочки потока.

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

Внутренние очереди и стратегии очереди

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

  • В случае потоков на чтение это блоки данных, которые были вставлены в очередь, но еще не были прочитаны
  • В случае потоков на запись это блоки данных, которые были записаны, но еще не были обработаны основным приемником.

Внутренние очереди используют стратегию очереди, которая определяет, как сигнализировать об обратной загрузке на основе состояния внутренней очереди.

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

Выполняемое вычисление

high water mark - total size of chunks in queue = desired size

Желаемый размер — это количество блоков данных, которые поток все еще может принять, чтобы поток продолжал течь, но при этом не превышал высокую отметку по размеру. Генерация блоков данных будет замедляться/ускоряться соответственно, чтобы поток течет как можно быстрее, но при этом желаемый размер оставался выше нуля. Если значение опустится до нуля (или ниже), это означает, что блоки данных генерируются быстрее, чем поток может с ними справиться, что может привести к проблемам.

В качестве примера, давайте возьмем размер блока данных 1 и высокую отметку 3. Это означает, что до 3 блоков данных могут быть вставлены в очередь, прежде чем будет достигнута высокая отметка и будет применена обратная загрузка.

© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API