Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Web Streams APIの基本と実践、TypeScriptでの活用法 / TSKaig...
Search
tasshi
May 23, 2025
Technology
3
250
Web Streams APIの基本と実践、TypeScriptでの活用法 / TSKaigi 2025 Web Streams API
TSKaigi 2025 のセッション資料です。
セッション情報はこちら↓
https://2025.tskaigi.org/talks/tasshi
tasshi
May 23, 2025
Tweet
Share
More Decks by tasshi
See All by tasshi
2024年のkintone API振り返りと2025年 / kintone API look back in 2024
tasshi
0
270
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
tasshi
2
520
GitHub Projectsを自動化するGitHub CLIテクニック / Automate GitHub Projects with GitHub CLI
tasshi
0
580
SDK開発チームのプロダクトオーナーが考えていること / Product management of SDK
tasshi
1
1.3k
Node.js製CLIツールのE2Eテストに取り組んでいます / Working on E2E testing of Node.js CLI tools
tasshi
0
1.4k
モダンな開発環境を用いた カンタン/安全なカスタマイズ開発 / kintone devCamp Boost! 2023
tasshi
0
840
Node Streamでメモリ性能改善、そしてWeb Streams APIへ / Improving memory performance of the CLI tool using Node Stream
tasshi
1
3.4k
グローバルチームことはじめ / Bootstrapping a global team
tasshi
1
3.8k
2年目サイボウズ社員とOSS / OSS development of junior engineer in Cybozu
tasshi
0
800
Other Decks in Technology
See All in Technology
トップエンジニアが語るDX最前線 / 20250517 Kazutoshi Ono & Ken Yamazaki
shift_evolve
0
110
The PyArrow revolution in Pandas
reuven
0
130
Azure の裏側を支える SRE の世界
tsubasaxzzz
2
360
激動の一年を通じて見えてきた「技術でリードする」ということ
ktr_0731
8
8.6k
Google CloudのAI Agent関連のサービス紹介
shukob
0
180
水耕栽培に全部賭けろ
mutsumix
0
170
インラインRBSコメントに鯛pe checkersもニッコリ
sansantech
PRO
2
220
名単体テスト 禁断の傀儡(モック)
iwamot
PRO
1
340
AIエージェントのオブザーバビリティについて
yunosukey
1
430
え!! 日本国内でGo言語のバイリンガル勉強会を!?
logica0419
2
110
開発も運用もビジネス部門も! クラウドで実現する「つらくない」統制とセキュリティ / Effortless Governance and Security Enabled by the Cloud
kanny
2
700
(なるべく)無料で始めるTerraformのインフラ構築体験
sakamossaaaan
1
110
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
32
5.8k
Adopting Sorbet at Scale
ufuk
76
9.4k
Making the Leap to Tech Lead
cromwellryan
133
9.3k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Git: the NoSQL Database
bkeepers
PRO
430
65k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Music & Morning Musume
bryan
47
6.5k
Being A Developer After 40
akosma
91
590k
A Tale of Four Properties
chriscoyier
159
23k
Transcript
Web Streams APIの 基本と実践、 TypeScriptでの活用法 2025.05.24 TSKaigi 2025 @tasshi_me 1
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages はじめに
田代 雅治 (@tasshi_me) • 仕事 • サイボウズ株式会社 • kintone開発 拡張基盤 チーム EM • DX (Developer eXperience) デザイン • 週4勤務、週1で副業 • 主にnpmパッケージとサーバーサイドJS • (画面はあまり触らない) • 去年から会社の同期とバンド始めました 自己紹介 2
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages はじめに
• kintone ≒ かんたんに業務アプリを構築できるクラウドサービス • kintoneのプラグイン・連携サービス向けの開発基盤を開発・保守するチーム • API開発、SDK/CLIなどのOSS提供 • npmパッケージを多数メンテナンス kintone開発 拡張基盤 チーム 3
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages はじめに
Streams APIを触ったことがないという声を聞くので、ざっくりStreams APIの説明をします。 また、Node Streamとの違いや、Promiseベースの非同期処理との相互運用性についても話します。 Streams APIを試すきっかけとなると良いかなと思います。 そして、今後の実装の選択肢にStreams APIが追加されたらとても嬉しいです。 (TSKaigiですが、型の話は少ないかも) このセッションでは 4
ストリームとは何か 5 ※様々な技術領域・開発言語でストリームの定義があるため ここでは概ね共通と思われる性質について話します
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages ストリームとは何か
• データ入出力を逐次的に、効率よく扱うためのデータ構造 • データをより細かい分割された単位の連続した流れとして表現する • 昔からある概念 • 多くの開発言語でストリーム操作のインターフェースは提供されている • 古くはUNIXの標準ストリーム、pipe、redirectとか ストリームとは何か 6 変換処理A chunk chunk chunk 変換処理B chunk chunk chunk 変換処理C chunk chunk chunk chunk
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages ストリームとは何か
標準ストリームとパイプの例 7 cat input .txt sed “foo” tee Terminal output .txt “bar” “bar” “bar” “foo” stdout stdin stdin stdout stdout
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages ストリームとは何か
• メモリ空間を圧迫しにくい • データを処理する分だけメモリ上に展開するため • 大規模データや時間経過で無限に増大するデータの処理に有効 • 低遅延 • 先頭のデータが処理されるまでの時間が速い • ※最終的にデータ全体が処理されるまでの時間が早くなるとは限らない ストリームのメリット 8 処理A 処理B ストリーム処理の場合 バッチ処理の場合 時間経過 時間経過
Web Streams API 9 WHATWGのStreams API (https://streams.spec.whatwg.org/)
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API JavaScriptでストリーム処理を行うためのAPI • データは分割された断片(chunk)の連続した流れとして扱われる • 3種類の役割の異なるストリームオブジェクト • ストリームオブジェクト同士をパイプ接続(パイプチェーン)することで、 chunkは流れるように終端まで処理される Streams APIの概要 10 Transform Stream Readable Stream Writable Stream chunk データの読み込み データの変換 (読み込み+書き込み) データの書き込み chunk Source Sink
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API 具体例: WebリソースをFetchしてファイルに保存 11 Text Decoder Stream Response. body FileSystem Writable FileStream string Uint8 Array example .com File System
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API 基となるソース(underlying source)から流れるデータを表現するオブジェクト ソースから流れるデータをチャンクに分割し、ストリーム処理できる形で提供する • 基となるソース:ファイルシステム、ネットワークリソース、メモリ上の配列、など • Pull型/Push型のソースがある(付録を参照) • ReadableStreamの例:Fetch APIのResponse.body、Blob.stream() ReadableStream (読み取り可能なストリーム) 12 Readable Stream chunk Source chunk 読み出し raw data
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API ストリームに流れるデータをある形式から別の形式に変換するオブジェクト • TransformStreamの例 • TextEncoderStream / TextDecoderStream: バイナリ 文字列の変換 • CompressionStream / DecompressionStream: データの圧縮・展開 (gzip, deflate) TransformStream (変換ストリーム) 13 chunk (string) chunk (Uint8Array) chunk (Uint8Array) TransformStream chunk (string)
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API 基となるシンク(underlying sink)に流れるデータを表現するオブジェクト • 基となるシンク:ファイルシステム、データベース、など • WritableStreamの例:File System Access APIのFileSystemWritableFileStream WritableStream (書き込み可能なストリーム) 14 Writable Stream chunk Sink chunk 書き込み data
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API • ReadableStream、TransformStream、 WritableStreamを継承して独自のストリームを作成する • データ処理用のいくつかのメソッドを実装する(pull, write, transform, etc.) • チャンクの型はGenericsで指定 • 後述のキューイング戦略もコンストラクタで指定 • DBアクセスとか、データエンコーディングとか、独自の処理を実装できる 独自のストリームオブジェクトを作成する 15
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API • Stream同士をパイプ接続すると、chunkは流れるように終端まで処理される(パイプチェーン) • パイプ接続メソッド • Readable.pipeTo(): 終端のWritableStreamに接続 • Readable.pipeThrough(): 中間のTransformStreamに接続 パイプチェーン 16 Transform Stream Readable Stream Writable Stream chunk chunk Source Sink pipeThrough() pipeTo()
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Streams
API • 1つのReadableStreamを2つのReadableStream(branch)に分配 • 分配したストリームはそれぞれ異なる速度で読み取ることができる • FetchしたデータをUIとキャッシュの両方に出力したりできる • 注:内部キューにチャンクが滞留するため、長すぎるデータストリームには適さない(付録を参照) ストリームの分配 (tee) 17 Readable Stream 元のストリーム Readable Stream 分配後のストリーム1 Source Readable Stream 分配後のストリーム2
利用イメージ 18 1. 他サービスからのデータインポート 2. GPTの回答をリアルタイム表示
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 利用イメージ
• メモリ負荷を軽減できる例 • 他サービスからAPI経由で全レコードを取得し、加工して自サービスのDBに書き込んでいく • APIのレスポンスはJSONL形式 1. 他サービスからのデータインポート 19 Text Decoder Stream Response JSON Parser Stream Line Splitter Stream 行ごとに 再分割 (Transform) UTF-8 デコード (Tranform) JSONから オブジェクトに変換 (Transform) レスポンスの 読み込み (Readable) Writable Stream DBに 書き込み (Writable) fetch DB
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 利用イメージ
• リアルタイム性を実現できる例 • API経由でGPTの回答を取得し、画面に表示する • デフォルトの一括応答では、回答全体が生成されてからレスポンスが返却される • ストリーミング応答を有効化すると、回答が生成された分ずつ返却されるようになる 2. GPTの回答をリアルタイム表示 20
内部キューと背圧 21 パイプチェーンの処理速度を調整する仕組みについて
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 内部キューと背圧
• ストリーム(オブジェクト)は未処理チャンクを保持する内部キューを持っている • パイプチェーン上のストリーム間で処理速度に差がある場合、 内部キューにチャンクが溜まっていくことになる => メモリを圧迫する? ストリームオブジェクト間の処理速度の違いとメモリ使用量 22 Transform Stream Readable Stream Writable Stream chunk chunk チャンクが溜まっていく? ここの処理が遅い場合 (DBアクセスなど) ※TransformStream は 書込側・読出側それぞれに 内部キューを持つが省略
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 内部キューと背圧
• チャンクを受け入れられない場合、ストリームは上流に停止信号を出す • 停止信号を受けた上流のストリームはデータの送信を停止する • 下流のストリームが送信を指示(pull)すると再び処理が再開する => チャンクの流速が調整されてメモリを圧迫せずに処理できる 背圧 (Backpressure) 23 Transform Stream Readable Stream Writable Stream chunk chunk 内部キューが満杯 STOP! 内部キューが満杯 STOP!
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 内部キューと背圧
• 背圧は内部キューの状態から、キューイング戦略に基づいて通知される • 現在は2種類のキューイング戦略が利用可能 キューイング戦略と最高水準点(highWaterMark) 24 キューに格納されたチャンク数で判定 キューに格納されたバイト数で判定 chunk chunk chunk chunk chunk chunk chunk chunk 3 最高水準点 (highWaterMark) 10KB CountQueuingStrategy ByteLengthQueuingStrategy
Node.jsのStreamとの違いと互換性 25 https://nodejs.org/api/stream.html
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• Node.jsの組み込みモジュール • こちらのほうが先発 • 「Streamを制するものはNode.jsを制す」と言われていたらしい • EventEmitterを継承していて、イベント駆動的 • highWaterMarkの考え方はNode StreamからWeb Streams APIに影響してそう • 3(+2)種類のストリームオブジェクト Node.js Streamについて 26 Readable 読み込み Duplex 双方向 (読み込み+書き込み) Transform 変換 Writable 書き込み PassThrou gh パススルー (何もしない)
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• Node.jsでもv21でWeb Streams APIがStableになった • Node Stream Web Streams API は toWeb() / fromWeb() メソッドで相互に変換可能 • v17で追加されてから長らくExperimentalだったが、v24でとうとうStableになった Node SteamとWeb Streams APIとの互換性 27
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• Web標準であること • クロスブラウザに利用できる • Fetch APIを始めとして、他の標準仕様にもWeb Streams APIベースのAPIが増えていっている • WinterTC Minimum Common APIにも含まれている • Node.js含めてサーバーサイドJSでも利用できる • インターフェースの改善 • EventEmitter/Callbackな書き方からPromise/async/awaitな書き方に • 利用者に公開されているメソッド・プロパティがかなり減っているため学習コストが減った • (逆に細かい制御がしづらくなったとも) • 型情報 (@types/node) • Node Stream: chunkの型がany • Web Streams API: chunkの型がGenericsで指定できる Node Streamと比べて良くなったと思うところ (1) 28
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• エラーハンドリング • Node Streamでは、上流のストリームがエラー終了しても下流のストリームが閉じない • errorイベントのイベントリスナーで明示的に閉じる必要がある • Web Streams APIでは、勝手に閉じる • pipeThrough()/pipeTo()のpreventAbortオプションで制御可能 Node Streamと比べて良くなったと思うところ (2) 29
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• 変換ストリームの結合が比較的やりやすくなった • Node Stream: Duplexでラップするが、実装が複雑になる • イベントリスナーやメソッドの繋ぎ込みがかなり面倒 • stream.compose()を利用すると簡単に結合できるが、まだExperimental • Web Streams API: TransformStreamでラップしてパイプ接続したらOK Node Streamと比べて良くなったと思うところ (3) 30
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Node.jsのStreamとの違いと互換性
• これから書くコードは最初からWeb Streams APIで良い • Web標準かつPromiseベースの書き方ができる • Node Streamとも toWeb() / fromWeb() で相互変換できる • 昔からあるnpmパッケージはNode Streamを使っている • 当面は toWeb() / fromWeb() メソッドで変換しながら併用することになる Node SteamとWeb Streams API、どっちを使えばいい? 31
Promiseベースの非同期処理との相互運用性 32 • ストリームとPromise • ストリームと反復処理
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Promiseベースの非同期処理との相互運用性
• pipeTo()の返り値がPromise • パイプチェーンでのデータ処理が終わるまでawaitで待つことができる • チャンクを1つずつ操作したい場合 • ReadableStream.getReader()やWritableStream.getWriter()でreader/writerを取得 • await reader.read() / await writer.write() でチャンクを1つずつ読み込み/書き込みできる ストリームをasync/awaitの中で使う 33
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Promiseベースの非同期処理との相互運用性
• ReadableStreamは非同期反復可能([Symbol.asyncIterator]()を実装している)(Safari除く) • for await ... ofで反復処理できる • Array.fromAsync()でデータを全て読み出して配列に格納できる ストリームを反復処理する 34
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages Promiseベースの非同期処理との相互運用性
• ReadableStream.from() • 反復可能オブジェクト or 非同期反復可能オブジェクトからReadableStreamを作成できる • ただしまだFireFox, Deno, Node.jsでしか利用できない イテラブルからストリームを作成する 35 https://developer.mozilla.org/ja/docs/Web/API/ReadableStream/from_static
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages おわりに
• Streams APIには3つのストリームオブジェクトがある • ReadableStream, TransformStream, WritableStream • ストリームオブジェクトをパイプ接続してデータを逐次処理できる • 背圧を制御することで処理速度を制御し、メモリ使用量を適切に抑えることができる • Node Streamとは相互に変換可能 • 新規に書くコードはWeb Streams APIで良い • async/awaitな処理とも組み合わせやすい まとめ 36
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages おわりに
• kintoneを開発する仲間を探しています!! • 採用フォームからでも、XのDMでもどうぞ! • https://cybozu.co.jp/recruit/ We are hiring!! 37 Webエンジニア (kintone) エンジニアリング マネージャー (kintone) Webエンジニア (kintone/生成AI) フロントエンド エキスパート
ご清聴ありがとうございました 38 Ask The Speakerやります! お気軽にご質問ください! 場所:3F 企画AREA 時間:13:50-14:00
付録 39 • ストリームオブジェクトの補足 • ストリームの分配 (tee) と背圧制御の問題 • ネットワーク通信に背圧は反映されているのか?
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 付録:ストリームオブジェクトの補足
• チャンクの読み込みはReader経由で行う • ソースにはPull型とPush型がある • Pull型:データはストリームから明示的に読み込む • 例:ファイルアクセスなど • https://streams.spec.whatwg.org/#example-rs-pull • Push型:データは勝手にソースから送信される、イベントリスナなどでストリームにenqueueする • 例:動画ストリーム、TCP/WebSocketsなど • https://streams.spec.whatwg.org/#example-rs-push-backpressure ReadableStream 40 Source chunk enqueue ReadableStream chunk chunk chunk chunk Reader 内部キュー raw data
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 付録:ストリームオブジェクトの補足
• チャンクの書き込みはWriter経由で行う WritableStream 41 Sink chunk enqueue WritableStream chunk chunk chunk chunk Writer 内部キュー data
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 付録:ストリームオブジェクトの補足
• 内部的にはWritableStream + ReadableStream • 入力側: TransformStream.writable (WritableStream) • 出力側: TransformStream.readable (ReadableStream) • 内部キューも入力側・出力側それぞれにある TransformStream (変換ストリーム) 42 readable chunk chunk writable chunk TransformStream transform() chunk データの入力側 データの出力側 データの変換
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 付録
• tee()で分配された2つのReadableStreamは消費速度が速い方の速度で背圧制御される • 時間経過と共に速度が遅い方の内部キューにデータが滞留してしまう • 背圧制御を変更するオプションが提案されている(whatwg/streams#1235) • Cloudflare Workersでは tee の背圧制御を独自に修正している(cloudflare/workerd#85) • https://community.cloudflare.com/t/467416 ストリームの分配 (tee) と背圧制御の問題 43 Readable Stream Readable Stream 両方に同時にchunkを送信 後続の 処理が速い 後続の 処理が遅い ここにチャンクが溜まってしまう
Web Streams APIの基本と実践、TypeScriptでの活用法 – TSKaigi 2025 #TSKaigi #TSKaigi2025 #tskaigi_leverages 付録
• 検証時の通信方式 • APIレスポンスはJSONL形式 (Content-Type: application/jsonl; charset=utf-8) • HTTP/1.1 • Transfer-Encoding: chunked (レスポンスはチャンク単位で送られてくる) • => 背圧はunderlying sourceへのネットワークリクエストにも反映される • 内部キューが溜まってくるとウィンドウサイズが小さくなり、受信可能データを調整する • それでも処理しきれずに受信を止める場合は、zero windowパケットが送信される ネットワーク通信に背圧は反映されているのか? 44 chunk Server chunk chunk Response STOP! STOP! (zero window) https://speakerdeck.com/tasshi/web-streams-api-and-tcp-flow-control