Javascript RxJS:异步变异树

Javascript RxJS:异步变异树,javascript,functional-programming,reactive-programming,rxjs,Javascript,Functional Programming,Reactive Programming,Rxjs,我有一系列需要通过向每个对象添加属性来异步修改的对象: [{ 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; 但是,在我的例子中,我

我有一系列需要通过向每个对象添加属性来异步修改的对象:

[{ 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); });

也许我一开始就不应该执行这种变异?

有什么理由需要创建两个单独的观察对象:一个用于正在更新的列表,另一个用于结果值

如果只是在原始列表上执行.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));
为了抽象此功能,我创建了一个helper函数,它将使用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));

当你说你有一个“深树”时,我假设你有一个递归数据结构,是吗?那么,仅仅使用递归函数并参数化级别之间发生的任何变化就足够了吗?在这两种情况下,您都已将
propertyvalue
创建为流。这有什么原因吗?如果不是,我建议您只从
map
操作返回增强对象。