【Rx.js】画像を非同期に読み込むサンプルコード
こんにちはー。
非同期の処理をいい感じに使える js のライブラリないかなーと探していたら、
Rx.js というのを見つけたので、それを使ったサンプル?を紹介します。
Rx.js とは?
.NET 向けの Reactive Extensions を js 用に移植したもの。
ぼくは、最初 .NET の方を使っていて、
「それの js 版があったらいいな~」と思っていたらピンポイントであったという感じですー。
コードの概要
では、今回書いてみるコードの概要を紹介します。
- 3つの画像が配列になっている
- それらを非同期で読むが、1つ読み終わったら次を読むという条件。
- 1つ読み終わった後と全部読み終わった後にコールバックする
全部いっぺんに非同期で読めばいいと思うかもしれませんが、
画像がウエーブみたいになって読み込まれていくようにしたかったんです。
【Before】Rx.js を使わない場合のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var images = ["1.png", "2.png", "3.png"]; function loadImages(oneByOne, finished) { var index = 0; var loadImage = name => { var elem = document.createElement("image"); elem.src = name; elem.onload = function() { oneByOne(index); if (index >= images.length - 1) { finished(); } else { loadImage(images[++index]); } } }; loadImage(images[index]); } function main() { loadImages(index => { console.log(index + "個目を読み込みました"); }, () => { console.log("読み込み完了"); }); }
|
このコードを、Rx.js を使って、シンプルにしてみます。
【After】Rx.js の降臨
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import Rx from "rx";
var images = ["1.png", "2.png", "3.png"]; function loadImages() { return Rx.Observable.create(loadImagesObservable); } function loadImagesObservable(observer) { var index = 0; var loadImage = name => { var elem = document.createElement("image"); elem.src = name; elem.onload = function() { observer.onNext(index); if (index >= images.length - 1) { observer.onCompleted(); } else { loadImage(images[++index]); } } }; loadImage(images[index]); return function() { }; } function main() { var subscription = loadImages().subscribe(index => { console.log(index + "個目を読み込みました"); }, err => { console.log("Observe Error: " + err); }, () => { console.log("読み込み完了"); }); }
|
- 1つ読み終わった時 →
observer.onNext
- 全部読み終わった時 →
observer.onCompleted
に当てはめました。
Rx.js を使うメリット
キャンセル時の処理を追加できる
上のコードでは書いていませんが、
subscription.dispose
でキャンセルでき、
loadImagesObservable の返り値の関数で、dispose された時の処理を追加できるので、
そこで読み込みの処理を停止するように書けば、簡単にできます!
キャンセル時の処理を書いた例: Gist
filter ができる
loadImages().subscribe(...)
を、loadImages().filter(...).subscribe(...)
にすれば、
フィルターを通すことも簡単にできます。
フィルターを使った例として、「5回に1回、○個目を読み込みましたと表示」するようにしてみます。
1 2 3 4 5 6 7 8 9 10
| function main() { var subscription = loadImages().filter(index => index % 5 === 0).subscribe(index => { console.log(index + "個目を読み込みました"); }, err => { console.log("Observe Error: " + err); }, () => { console.log("読み込み完了"); }); }
|
フィルターを利用した例の全コード: Gist
参考
追記
2016-04-07 : Rx.js を使ったメリットを中心とするように記事の内容を全面改訂。