2

各オブジェクトにプロパティを追加して、非同期的に変更する必要がある一連のオブジェクトがあります。

[{ id: 1 }, { id: 2 }] => [{ id: 1, foo: 'bar' }, { id: 2, foo: 'bar' }]

これに相当する同期は次のようになります。

var xs = [{ id: 1 }, { id: 2 }];
// Warning: mutation!
xs.forEach(function (x) {
    x.foo = 'bar';
});

var newXs = xs;

ただし、私の場合、fooプロパティを非同期的に追加する必要があります。fooプロパティが追加されたオブジェクトのシーケンスを終了値にしたいと思います。

この問題を解決するために、次のコードを思いつきました。この例では、各オブジェクトに の値を持つプロパティを追加していますbar

var xs = Rx.Observable.fromArray([{ id: 1 }, { id: 2 }]);
var propertyValues = xs
    // Warning: mutation!
    .flatMap(function (x) {
        return Rx.Observable.return('bar');
    });

var newXs =
    .zip(propertyValues, function (x, propertyValue) {
        // Append the property here
        x.foo = propertyValue;
        return x;
    })
    .toArray();

newXs.subscribe(function (y) { console.log(y); });

これは私の問題を解決する最良の方法ですか、それとも Rx はシーケンス内のオブジェクトを非同期的に変更するためのより良い手段を提供しますか? 変更する必要がある深いツリーがあり、このコードはすぐに扱いにくくなるため、よりクリーンなソリューションを探しています。

var xs = Rx.Observable.fromArray([{ id: 1, blocks: [ {} ] }, { id: 2, blocks: [ {} ] } ]);
var propertyValues = xs
    // Warning: mutation!
    .flatMap(function (x) {
        return Rx.Observable.fromArray(x.blocks)
            .flatMap(function (block) {
                var blockS = Rx.Observable.return(block);

                var propertyValues = blockS.flatMap(function (block) {
                    return Rx.Observable.return('bar');
                });

                return blockS.zip(propertyValues, function (block, propertyValue) {
                    block.foo = propertyValue;
                    return block;
                });
            })
            .toArray();
    });

xs
    .zip(propertyValues, function (x, propertyValue) {
        // Rewrite the property here
        x.blocks = propertyValue;
        return x;
    })
    .toArray()
    .subscribe(function (newXs) { console.log(newXs); });

そもそも、この突然変異を行うべきではないのでしょうか?

4

1 に答える 1

0

2 つの別々の Observables を作成する必要がある理由はありますか? 1 つは更新するリスト用で、もう 1 つは結果の値用ですか?

元のリストに対して .map() を実行するだけで、非同期にリストを更新して結果を購読できるはずです。

// This is the function that generates the new property value
function getBlocks(x) { ... }

const updatedList$ = Rx.Observable.fromArray(originalList)
    // What we're essentially doing here is scheduling work
    // to be completed for each item
    .map(x => Object.assign({}, x, { blocks: getBlocks(x)}))
    .toArray();

// Finally we can wait for our updatedList$ observable to emit
// the modified list
updatedList$.subscribe(list => console.log(list));

この機能を抽象化するために、setTimeout を使用して各項目の作業を明示的にスケジュールするヘルパー関数を作成しました。

function asyncMap(xs, fn) {
    return Rx.Observable.fromArray(xs)
        .flatMap(x => {
            return new Rx.Observable.create(observer => {
                setTimeout(() => {
                    observer.onNext(fn(x));
                    observer.completed();
                }, 0);
            });
        })
        .toArray();
}

この機能を使用して、各アイテムの完了作業をスケジュールできます。

function updateItem(x) {
    return Object.assign({}, x, { blocks: getBlocks(x) }
}

var updatedList$ = asyncMap(originalList, updateItem);
updateList$.subscribe(newList => console.log(newList));
于 2016-03-01T16:18:48.720 に答える