ブラウザで1行JSONをストリーミングするライブラリを作ったので、紹介したいと思います。
使い方
このライブラリは https://deno.land/ から配信されているため、https://deno.land/x/jsonlines@v1.2.1/js/mod.js
というURLをインポートするだけで使えます。
以下のような1行JSONがあったとします。
{"id": 1, "data": ["xxxxx", "yyyyyyyy"]}
{"id": 2, "data": ["bbb", "aaaaaa"]}
...(以下無限に流れてくる)
これを1行ずつ読み取って、JSONとしてパースして順次読み込むには、以下のようにします。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="module">
import { JSONLinesParseStream } from "https://deno.land/x/jsonlines@v1.2.1/js/mod.js";
// ①サンプル用の1行JSONをfetch
const { body } = await fetch("https://deno.land/x/jsonlines@v1.2.1/testdata/json-lines.jsonl");
// ②pipeThroughで、ストリーミングされてくるデータを変換
const readable = body
.pipeThrough(new TextDecoderStream())
.pipeThrough(new JSONLinesParseStream());
// ③ for-await-of文でデータを読み出し
for await (const data of readable) {
console.log(data); // 変数dataの中にパース結果のJSONが入っている
}
</script>
</head>
<body></body>
</html>
使い方としては、
⓪ ライブラリをimport
① fetch(url)
を使ってデータを読み込み
② body.pipeThrough(変換関数)
でデータを変換(ここでJSONをパース)
③ for-await-of
文を使ってデータを読み込み
という形になります。
どうやって実装されているか
TransformStream
JavaScriptでデータをストリーミングする際はWeb Stream APIを使用します。
fetch()
の返り値なども、このWeb Stream APIに対応しています。
さて、Web Stream APIにはストリーミングしている途中にデータを書き換えるTransformStreamというものがあります。今回は、TransformStreamをカスタムして任意の変換処理ができるようにしていきました。
export class JSONLinesParseStream implements TransformStream<string, JSONValue> {
readonly writable: WritableStream<string>;
readonly readable: ReadableStream<JSONValue>;
constructor(options: ParseStreamOptions = {}) {
this.writable = ...;
this.readable = ...;
}
}
なお、このTransformStreamですが、現時点ではFireFox非対応です。
今後のバージョンでサポートが追加されるようなので、このライブラリが全モダンブラウザで使えるようになるのはちょっと先になりそうです。
余談ですが、最近Firefoxのサポートを切って話題になったサービスは動画系サービスが多いような気がします。ストリーミングAPIの対応状況の悪さがサポートを切る一因になったのではと邪推しているのですが……