オブザーバブルの再帰チェーンに問題がありました。
現在バージョン 1.0.10621 の RxJS を使用しており、Rx for jQuery と組み合わせて、最も基本的な Rx 機能が含まれています。
私の問題のシナリオ例を紹介しましょう。特定のキーワードを含むツイート/更新について、 Twitter 検索 API (JSON 応答) をポーリングしています。応答には、フォローアップ要求を生成するために使用する「refresh_url」も含まれます。そのフォローアップ リクエストへの応答には、新しい refresh_url などが含まれます。
Rx.jQuery を使用すると、Twitter 検索 API 呼び出しを監視可能なイベントにすることができます。これにより、onNext が生成されて完了します。私がこれまでに試したことは、onNext ハンドラーに refresh_url を記憶させ、それを onCompleted ハンドラーで使用して、次のリクエスト用に新しいオブザーバブルと対応するオブザーバーの両方を生成することです。このようにして、1 つのオブザーバブル + オブザーバーのペアが、もう一方のペアに無期限に続きます。
このアプローチの問題は次のとおりです。
フォローアップのオブザーバブル/オブザーバーは、前任者がまだ破棄されていないときにすでに生きています。
現在生きているオブザーバーへの有効な参照を維持するために、多くの厄介な簿記を行う必要があります。実際には、そのうちの2つが存在する可能性があります。(1 つは onCompleted にあり、もう 1 つはそのライフサイクルの別の場所にあります) もちろん、この参照は、オブザーバーの購読を解除/破棄するために必要です。簿記の代わりに、私の例で行ったように、「まだ実行中ですか?」ブール値を使用して副作用を実装することです。
コード例:
running = true;
twitterUrl = "http://search.twitter.com/search.json";
twitterQuery = "?rpp=10&q=" + encodeURIComponent(text);
twitterMaxId = 0; //actually twitter ignores its since_id parameter
newTweetObserver = function () {
return Rx.Observer.create(
function (tweet) {
if (tweet.id > twitterMaxId) {
twitterMaxId = tweet.id;
displayTweet(tweet);
}
}
);
}
createTwitterObserver = function() {
twitterObserver = Rx.Observer.create(
function (response) {
if (response.textStatus == "success") {
var data = response.data;
if (data.error == undefined) {
twitterQuery = data.refresh_url;
var tweetObservable;
tweetObservable = Rx.Observable.fromArray(data.results.reverse());
tweetObservable.subscribe(newTweetObserver());
}
}
},
function(error) { alert(error); },
function () {
//create and listen to new observer that includes a delay
if (running) {
twitterObservable = $.getJSONPAsObservable(twitterUrl, twitterQuery).delay(3000);
twitterObservable.subscribe(createTwitterObserver());
}
}
);
return twitterObserver;
}
twitterObservable = $.getJSONPAsObservable(twitterUrl, twitterQuery);
twitterObservable.subscribe(createTwitterObserver());
リクエストからツイートまで、オブザーバブル/オブザーバーの二重層に惑わされないでください。私の例は、主に最初の層、つまり Twitter からのデータの要求に関するものです。この問題を解決するために、2 番目の層 (応答をツイートに変換する) が最初の層と 1 つになることができれば、それは素晴らしいことです。でも、それは全くの別物だと思います。今のところ。
Erik Meijer は私に Expand 演算子を指摘し (以下の例を参照)、代替としてJoin パターンを提案しました。
var ys = Observable.Expand
(new[]{0}.ToObservable() // initial sequence
, i => ( i == 10 ? Observable.Empty<int>() // terminate
: new[]{i+1}.ToObservable() // recurse
)
);
ys.ToArray().Select(a => string.Join(",", a)).DumpLive();
これは、LINQPad にコピーして貼り付けることができます。シングルトンのオブザーバブルを想定し、最終的なオブザーバーを 1 つ生成します。
だから私の質問は次のとおりです:RxJSで最も優れた展開トリックを行うにはどうすればよいですか?
編集:
展開演算子は、おそらくこのスレッドに示されているように実装できます。しかし、ジェネレーターが必要になります(そして、私は JS < 1.6 しか持っていません)。
残念ながら、RxJS 2.0.20304-betaは Extend メソッドを実装していません。