阵列突变而不触发特定的观察者

Array mutation without triggering a specific observer

本文关键字:观察者 突变 阵列      更新时间:2023-09-26

我正在使用web套接字将属性boardBucket的更改传输到其他客户端。

  • CCD_ 2是由观察者观察的CCD_ 3类型的共享属性。

  • 当观测者收到更改通知时,这些更改将通过套接字发送到其他客户端,在那里它们将应用于自己的boardBucket

现在的问题变成了如何防止某些对象更改(通过数组突变方法this.set()this.push()等)重新触发发送更改的特定观察者。

如果没有某种静音功能,整个设置将在客户端之间进行无限的往返(一个客户端更改boardBucket,另一个客户端应用更改,但这也会触发它自己的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的路径/值相同,则忽略它而不发送它。但是,我希望有一种方法可以防止其他一些突变到达套接字发送函数,因此这不起作用。这也有点古怪

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

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;
}

这似乎也有点棘手,我对这种方法的局限性的理解如下:

如果(并且仅当)this.set在返回之前准确地传递了传递给它的更改,那么这应该有效。如果它传递更多的更改,或者传递异步传递的更改,那么这将不起作用。查看我们拥有的Polymer变更通知协议文档:

当属性更改时,元素会触发一个非冒泡DOM事件,将这些更改指示给感兴趣的主机。

如果使用了DOM事件,我认为应该在this.set调用返回之前交付它。

因此,我认为出现这种问题的唯一机制是,如果有人在听boardbucket的话,决定对你的更改做出更改——我想你应该控制你的应用程序,而且在任何情况下,这似乎都是一件坏事。如果发生这种情况,我看不出任何回应是有效的;要么忽略这些"响应更改而进行的更改",boardbucket在客户端之间变得不同步,要么通过套接字发送它们,然后返回到潜在的循环。

更详细地说,如果我们将响应更改的更改称为更改^2,那么代码只会阻止将更改^2发送到套接字。如果更改^2对其他客户没有意义,那么这是正确的行为。如果更改^2对其他客户端有意义,那么我想它们需要被发送到套接字,但这将是低效的,因为它使用通过网络的循环来更新数据,而这种方式可能不是对用户输入的响应。我想这样的更改^2最好由看到原始更改的客户端进行——它可以计算出需要^2对将要发送的现有更改进行哪些更改,并将其添加到中以一次性发送。这样只需要一次网络传输,并且任何接收客户端都知道数据是有效的,不会触发任何更改^2。