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
6
1.4k
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
280
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
tasshi
2
560
GitHub Projectsを自動化するGitHub CLIテクニック / Automate GitHub Projects with GitHub CLI
tasshi
0
620
SDK開発チームのプロダクトオーナーが考えていること / Product management of SDK
tasshi
1
1.4k
Node.js製CLIツールのE2Eテストに取り組んでいます / Working on E2E testing of Node.js CLI tools
tasshi
0
1.4k
モダンな開発環境を用いた カンタン/安全なカスタマイズ開発 / kintone devCamp Boost! 2023
tasshi
0
870
Node Streamでメモリ性能改善、そしてWeb Streams APIへ / Improving memory performance of the CLI tool using Node Stream
tasshi
1
3.5k
グローバルチームことはじめ / Bootstrapping a global team
tasshi
1
3.8k
2年目サイボウズ社員とOSS / OSS development of junior engineer in Cybozu
tasshi
0
810
Other Decks in Technology
See All in Technology
生成AI時代 文字コードを学ぶ意義を見出せるか?
hrsued
1
680
Tokyo_reInforce_2025_recap_iam_access_analyzer
hiashisan
0
130
Model Mondays S2E03: SLMs & Reasoning
nitya
0
230
整頓のジレンマとの戦い〜Tidy First?で振り返る事業とキャリアの歩み〜/Fighting the tidiness dilemma〜Business and Career Milestones Reflected on in Tidy First?〜
bitkey
0
170
モバイル界のMCPを考える
naoto33
0
300
AI専用のリンターを作る #yumemi_patch
bengo4com
1
270
Microsoft Build 2025 技術/製品動向 for Microsoft Startup Tech Community
torumakabe
2
320
作曲家がボカロを使うようにPdMはAIを使え
itotaxi
0
370
「良さそう」と「とても良い」の間には 「良さそうだがホンマか」がたくさんある / 2025.07.01 LLM品質Night
smiyawaki0820
1
420
生成AI時代の開発組織・技術・プロセス 〜 ログラスの挑戦と考察 〜
itohiro73
1
360
asken AI勉強会(Android)
tadashi_sato
0
130
タイミーのデータモデリング事例と今後のチャレンジ
ttccddtoki
2
340
Featured
See All Featured
Building Adaptive Systems
keathley
43
2.6k
Rebuilding a faster, lazier Slack
samanthasiow
82
9.1k
Music & Morning Musume
bryan
46
6.6k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
940
We Have a Design System, Now What?
morganepeng
53
7.7k
It's Worth the Effort
3n
185
28k
4 Signs Your Business is Dying
shpigford
184
22k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
Mobile First: as difficult as doing things right
swwweet
223
9.7k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
48
5.4k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
Faster Mobile Websites
deanohume
307
31k
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