9

オブザーバブルの再帰チェーンに問題がありました。

現在バージョン 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 つのオブザーバブル + オブザーバーのペアが、もう一方のペアに無期限に続きます。

このアプローチの問題は次のとおりです。

  1. フォローアップのオブザーバブル/オブザーバーは、前任者がまだ破棄されていないときにすでに生きています。

  2. 現在生きているオブザーバーへの有効な参照を維持するために、多くの厄介な簿記を行う必要があります。実際には、そのうちの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 メソッドを実装していません。

4

1 に答える 1

4

だから私はあなたの問題をあなたがしたのとは少し違った方法で解決しようと試み、あなたがより簡単に解決できる自由をいくつか取っています.

だから私が言えないことの1つは、あなたが次のステップを試みているということです

  • 次の URL を含む最初のツイート リストを取得する
  • ツイート リストが受信されると、現在のオブザーバーを onNext し、次の一連のツイートを取得します。
    • これを無期限に行う

または、ユーザー アクションがありますか (get more / 一番下までスクロール)。いずれにせよ、それは本当に同じ問題です。私はあなたの問題を間違って読んでいるかもしれません。これがその答えです。

function getMyTweets(headUrl) {
    return Rx.Observable.create(function(observer) {

        innerRequest(headUrl);
        function innerRequest(url) {
            var next = '';

            // Some magic get ajax function
            Rx.get(url).subscribe(function(res) {
                observer.onNext(res);
                next = res.refresh_url;
            },
            function() {
                // Some sweet handling code
                // Perhaps get head?
            },
            function() {
                innerRequest(next);
            });
        }
    });
}

これはあなたが求めていた答えではないかもしれません。そうでない場合は、申し訳ありません!


編集:コードを調べた後、結果を配列として取得して観察したいようです。

// From the results perform a select then a merge (if ordering does not matter).
getMyTweets('url')
    .selectMany(function(data) {
        return Rx.Observable.fromArray(data.results.reverse());
    });

// Ensures ordering
getMyTweets('url')
    .select(function(data) {
        return Rx.Observable.fromArray(data.results.reverse());
    })
    .concat();
于 2013-12-24T04:26:54.337 に答える