Rxjs 观察对象更新和变化

Posted

技术标签:

【中文标题】Rxjs 观察对象更新和变化【英文标题】:Rxjs observing object updates and changes 【发布时间】:2015-12-17 11:03:17 【问题描述】:

我目前正在尝试观察给定对象的任何变化,包括它的所有元素。

以下代码仅在更新 object[x] 时触发,但不会在单独更新 object[x] 的元素(例如 object[x][y])时触发

<script>
  var elem = document.getElementById("test1");

var log = function(x) 
    elem.innerhtml += x + "<br/><br/><br/>";
;

var a = [a:1,b:2,
         a:2,b:5
       ];


var source = Rx.Observable
.ofObjectChanges(a)
.map(function(x) 
    return JSON.stringify(x);
);


var subscription = source.subscribe(
    function (x) log(x);,
    function (err) log(err);,
    function () log('Completed');
);

a[0] = a[1];
</script>

此代码正确运行和触发。

然而。如果我改为这个

a[0]['a'] = 3;

然后什么都没有发生。

编辑

更好的表达方式是,如何观察对象数组的变化?

【问题讨论】:

可能从使用ofArrayChanges 开始。 【参考方案1】:

这是一个 Rx.Observable.ofNestedObjectChanges 简单实现的工作示例,您可以了解它的要点并自己实现。

http://jsbin.com/wekote/edit?js,console

        Rx.Observable.ofNestedObjectChanges = function(obj) 
            if (obj == null)  throw new TypeError('object must not be null or undefined.'); 
            if (typeof Object.observe !== 'function' && typeof Object.unobserve !== 'function')  throw new TypeError('Object.observe is not supported on your platform') 
            return new Rx.AnonymousObservable(function(observer) 
                function observerFn(changes) 
                    for(var i = 0, len = changes.length; i < len; i++) 
                        observer.onNext(changes[i]);
                    
                
                Object.observe(obj, observerFn);
                //Recursive observers hooks - same observerFn
                traverseObjectTree(obj, observerFn);

                function traverseObjectTree(element, observerFn)
                    for(var i=0;i<Object.keys(element).length;i++)
                        var myObj = element[Object.keys(element)[i]];
                        if(typeof myObj === "object")
                            Object.observe(myObj, observerFn);
                            traverseObjectTree(myObj,observerFn);
                        
                    
                

                return function () 
                    Object.unobserve(obj, observerFn);
                ;
            );
        ;



        //Test
        var json = 
            element : 
                name : "Yocto",
                job : 
                    title: "Designer"
                
            ,
            element1: 
                name : "Mokto"
            
        ;

        setTimeout(function()
            json.element.job.title = "A Great Designer";
        ,3000);


        var source = Rx.Observable.ofNestedObjectChanges(json);

        var subscription = source.subscribe(
            function (x) 
                console.log(x);
            ,
            function (err) 
                console.log('Error: %s', err);
            ,
            function () 
                console.log('Completed');
            );

        json.element.name = "Candy Joe";

【讨论】:

已在 Safari 和 Chrome 中签出。链接提供的片段似乎已损坏。【参考方案2】:

通过合并两个 Observables(一个用于数组,另一个用于观察数组的元素)可能是这样的:

var a = [
  a:1,b:2,
  a:2,b:5
];


var source1 = Rx.Observable.ofArrayChanges(a).map(function(x) 
  return JSON.stringify(x);
);

var source2 = Rx.Observable
.fromArray(a.map(function(o, i)  return [o, i]; ))
.flatMap(function(oi) 
  return Rx.Observable.ofObjectChanges(oi[0])
  .map(function(x) 
    var y = 
      type: x.type,
      object: x.object,
      name: x.name,
      oldValue: x.oldValue,
      arrayIndex: oi[1] // pass the index of the member that changed
    ;
    return JSON.stringify(y);
  );
)

source = source1.merge(source2)

var subscription = source.subscribe(
  function (x) log(x);,
  function (err) log(err);,
  function () log('Completed');
);


a[0] = a[1]
a[1]['b'] = 7

感谢@electrichead,我们没有使用concatMap,因为我们由ofObjectChangesofArrayChanges 制作的资源从未完成。

【讨论】:

【参考方案3】:

如果您只想更改嵌套对象:

var source = rx.Observable.from(a).flatMap(function(item) 
  return rx.Observable.ofObjectChanges(item);
);

如果您还想要更改 a[0] = a[1]:

var source = rx.Observable.merge(
  rx.Observable.ofArrayChanges(a),
  rx.Observable.from(a).flatMap(function(item) 
    return rx.Observable.ofObjectChanges(item);
  )
);

flatMapselectMany(它们是同一个函数)将允许您迭代一个值并执行一个返回 Observable 的函数。所有这些 Observable 的值都被“展平”到返回的新流上。

http://reactivex.io/documentation/operators/flatmap.html

【讨论】:

为了使它工作,我需要将 rx 更改为 Rx 并在合并结束时添加 map 函数。酷! 'rx.Observable.ofObjectChanges' 已贬值。 是的,看到这个方法已经贬值了,我很想看看如何在 RxJS 5 中观察对象的变化......

以上是关于Rxjs 观察对象更新和变化的主要内容,如果未能解决你的问题,请参考以下文章

缺少可观察的方法 RxJS 5.0.0-beta.0

rxjs入门指南

更新可观察打字稿中的数组值

Angular/RxJS:带有可观察对象的嵌套服务调用

一个一个可观察的 RxJS

rxjs简单入门