数组变异而不触发特定的观察者

时间:2016-03-27 12:48:32

标签: javascript polymer polymer-1.0

我使用网络套接字将属性boardBucket的更改传输给其他客户端。

  • boardBucket是观察者观看的Object类型的共享属性。

  • 当观察者收到更改通知时,更改将通过套接字发送到其他客户端,并将其应用于自己的boardBucket

现在的问题是如何阻止某些对象更改(通过Array mutation methods this.set()this.push()等)重新触发该特定观察者发送更改。

如果没有某种静默功能,整个设置将进入客户端之间的无限往返(一个客户端更改boardBucket,其他客户端应用更改但是也会触发它#39;自己的boardBucket观察者,然后重新发送它们。

是否可以更改属性(或其任何子项)的值,而不用以某种方式触发特定的观察者?

    properties: {
      boardBucket: {
        type: Object,
        value: null,
        notify: true
      }
    },

    observers: [
      "_boardBucketChanged(boardBucket.*)"
    ],

    // if my `boardBucket` changes send changes to other clients
    _boardBucketChanged: function(changes) {
      sockets.send(changes);
    },

    // get changes sent by other clients and apply them
    _boardBucketReceived: function(changes) {

      // How can I silently make the following changes 
      // so it doesn't trigger **only** the above observer?
      this.set("boardBucket", changes); 
    }

理想情况下,在改变一个可以在观察者中拾取的对象/数组时,可以传递一个标志:

    // flag can be read in observer
    _boardBucketChanged: function(changes, flag) {
      if(flag === "preventNotify") return false;
      sockets.send(changes);
    },

    // `flag` parameter can be passed with each mutation
    _boardBucketReceived: function(changes) {
      if(flag === "preventNotify") 
        return false;
      this.set("boardBucket", changes, "preventNotify"); 
    }

注意

  • 我也可以使用<iron-signals>(即事件)代替观察者,但我更愿意避开它们,因此这个问题。
  • boardBucket是由多个内部组件共享的属性,每个组件都会发生变异并进行观察。这就是我在询问是否只有一个特定的观察者在变异时可以跳过的原因。
  • 我可以在传入/传出更改之间进行一些相等检查,如果changes的路径/值相同,则忽略它而不发送它。但是,我想有办法防止其他一些突变到达套接字发送功能,因此这不会起作用。它也有点hacky。

1 个答案:

答案 0 :(得分:1)

我很想知道如果你这样做会发生什么:

properties: {
  boardBucket: {
    type: Object,
    value: null,
    notify: true
  },
  settingBucket: {
    type: Boolean,
    value: false
  }
},

observers: [
  "_boardBucketChanged(boardBucket.*)"
],

// if my `boardBucket` changes send changes to other clients
_boardBucketChanged: function(changes) {
  //If we're setting, this is our change.
  //TODO: Is there any way that we can receive a change while
  //setting that is NOT the result of calling this.set? For
  //example if changes are batched and sent at once?
  if (!this.settingBucket) sockets.send(changes);
},

// get changes sent by other clients and apply them
_boardBucketReceived: function(changes) {
  //We are currently setting bucket, so ignore received changes
  this.settingBucket = true;
  this.set("boardBucket", changes); 
  //Now we're done
  this.settingBucket = false;
}

这看起来有点hacky,我对这种方法局限性的理解如下:

如果(且仅当)this.set在返回之前准确传递了传递给它的更改,那么这应该有效。如果它提供任何更改,或者提供更改,它将异步传递,那么这将不起作用。  查看我们的Polymer docs for Change notification protocol

“当属性发生更改时,该元素会触发一个非冒泡的DOM事件,以指示对感兴趣的主机的更改。”

鉴于使用了DOM事件,我认为它应该在this.set调用返回之前传递。

所以我觉得这个出错的唯一机制就是如果有人听到董事会决定根据你的变化做出改变 - 我想你应该控制你的应用程序,看起来它会在任何情况下都是一件坏事。如果发生这种情况,我看不出对它的任何回应是有效的;要么你忽略了这些“响应变化的变化”,而且客户之间的董事会变得越来越少,或者你通过套接字发送它们,你就会回到潜在的循环中。

更详细地说,如果我们将响应变化的变化称为变化^ 2,那么代码只会阻止更改^ 2被发送到套接字。如果更改^ 2对其他客户端没有意义,那么这是正确的行为。如果更改^ 2对其他客户端有意义,那么他们需要将它们发送到套接字我猜,但这样效率很低,因为它使用循环通过网络来更新数据的方式可能不是响应于用户输入。我猜这些改变^ 2会更好地由看到原始更改的客户端做出 - 它可以解决为了响应它将要发送的现有更改所需的更改^ 2,并添加它们以通过所有发送立刻。这样只需要一次网络传输,任何接收客户端都知道数据有效,不会触发任何更改^ 2.