首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >notifier.performChange实际上是做什么的?

notifier.performChange实际上是做什么的?
EN

Stack Overflow用户
提问于 2014-11-25 05:19:49
回答 2查看 371关注 0票数 4

我在试着理解Object.getNotifier(object).performChange。从概念上讲,我理解它是为定义“宏”或更高级别的变化而设计的。来自每个人都提到的例子

代码语言:javascript
复制
increment: function(amount) {
  var notifier = Object.getNotifier(this);

  notifier.performChange(Thingy.INCREMENT, function() {
    this.a += amount;
    this.b += amount;
  }, this);

  notifier.notify({
    object: this,
    type: Thingy.INCREMENT,
    incremented: amount
  });
}

我不明白的是,这与直接执行直接传递给notifier.performChange的匿名函数而不是作为回调有什么不同?换言之,它与以下内容有何不同:

代码语言:javascript
复制
increment: function(amount) {
  var notifier = Object.getNotifier(this);

  this.a += amount;
  this.b += amount;

  notifier.notify({
    object: this,
    type: Thingy.INCREMENT,
    incremented: amount
  });
}

我已经看到,在最新的规范中,notifier.performChange可能返回一个对象,然后作为通知发出该对象,如下所示:

代码语言:javascript
复制
notifier.performChange(Thing.INCREMENT, function() {
    this.a += amount;
    this.b += amount;

    // a notification is issues with this return value,
    // including the type passed to notifier.performChange,
    // and the object underlying notifier. 
    return {incremented: amount};  
});

这就消除了原始代码中对下面的notifier.notify的需求,但是,这是糖之外的东西吗,还是在功能上与只进行更改并自己发出通知之间有区别?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-12-01 02:15:26

经过一个小时的测试,我终于找到了答案。我有同样的问题( performChange是用来做什么的?),也有相同的想法就是把它关掉然后打电话。

代码语言:javascript
复制
this.a += amount;
this.b += amount;

但是:notifier.performChange的要点是使观察者不观察每个变化。

我是这样测试的:

代码语言:javascript
复制
var obj = {
  x: 5,
  y: 10
};

function noti() {
  console.log('noti start');
  var notifier = Object.getNotifier(obj);

  notifier.performChange('ok', function() {
    obj.x++;
    obj.y++;
  });

  notifier.notify({
    type: 'ok',
    oldValue: 5
  });
  console.log('noti end');
};

function noti2() {
  console.log('noti2 start');
  var notifier = Object.getNotifier(obj);

  obj.x++;
  obj.y++;

  notifier.notify({
    type: 'ok',
    oldValue: 5
  });
  console.log('noti2 end');
};

function observer(changes) {
  for (var change of changes) {
    console.log('observer: change =', change, ' newValue=', change.object[change.name]);
  }
};

Object.observe(obj, observer, ['ok', 'update']);

console.log('calling noti2()');
noti2(); //will log the changes of update twice becuase of the x and y property of obj

// add delay manually because observer calls are asynchronous and
// we want to clearly separate the notification function calls in our logs
setTimeout(function() {
  console.log('calling noti()');

  noti(); //will only log the ok type. that's what they mean by big change
          //so everything you do inside the performChange won't be observed
}, 100);

它应该返回以下控制台输出:

代码语言:javascript
复制
calling noti2()
noti2 start
noti2 end
observer: change = Object {type: "update", object: Object, name: "x", oldValue: 5}  newValue= 6
observer: change = Object {type: "update", object: Object, name: "y", oldValue: 10}  newValue= 11
observer: change = Object {object: Object, type: "ok", oldValue: 5}  newValue= undefined

calling noti()
noti start
noti end
observer: change = Object {object: Object, type: "ok", oldValue: 5}  newValue= undefined
票数 4
EN

Stack Overflow用户

发布于 2014-12-18 21:10:36

我想给出一个明确的答案,我也在问自己,所以我看了一下Object.observe规范

下面是您需要了解的关于Object.getNotifier(obj).performChange(changeType, changeFn)所做的事情:

  • 它运行changeFn
  • changeFn运行时,它故意不将obj属性可能发生的更改通知任何观察者
  • 您可以让changeFn返回一个对象:obj的观察者将收到该对象自身属性的通知。

为了自己看看,%NotifierPrototype%.performChange(changeType, changeFn)是您要在规范中寻找的东西。

应用到您的示例中,这意味着这两个结果完全相同,同时所做的事情略有不同:

示例1:

代码语言:javascript
复制
increment: function(amount) {
    var notifier = Object.getNotifier(this);

    notifier.performChange(Thingy.INCREMENT, function() {
        this.a += amount;
        this.b += amount;
    });

    notifier.notify({
        object: this,
        type: Thingy.INCREMENT,
        incremented: amount
    });
}

在第一个例子中:

  • 根据performChange()的行为,对回调函数中对象属性的更改将保持沉默。
  • 因为回调函数返回undefined,所以performChange()不会通知任何观察者其他任何事情
  • 但是,在最后调用notify()会显式地通知相应的观察者所传递的更改记录。

示例2:

代码语言:javascript
复制
increment: function(amount) {
    var notifier = Object.getNotifier(this);

    notifier.performChange(Thingy.INCREMENT, function() {
        this.a += amount;
        this.b += amount;

        return { incremented: amount };  
    });
}

在第二个例子中:

  • 根据performChange()的行为,对回调函数中对象属性的更改将保持沉默。
  • 由于回调函数返回一个对象,因此performChange()将使用一个与在示例1:{ object: Object, type: Thingy.INCREMENT, increment: amount }中显式调用notify()所产生的对象相同的对象通知适当的观察者。

这两个示例应该涵盖您希望使用performChange()的大多数情况,以及如何使用它。我要继续潜水,因为这只野兽的行为很有趣。

异步性

观察者是异步执行的。这意味着上面示例中的increment()函数内部发生的一切实际上都是在increment()完成执行之后向观察者报告的--而且只有到那时才报告。

换言之,所有这些:

  • performChange()之外对观察到的对象的属性进行更改
  • performChange()的回调中返回一个对象
  • 调用notify()

只会在increment()运行完毕后通知适当的观察者。

同步变更交付

如果您需要知道在increment()执行过程中的挂起的更改(pending =将在increment()结束时向观察者报告的所有更改,但尚未报告),那么就有一个解决方案:Object.deliverChangeRecords(callback)

但是,请注意,callback需要是对您以前已经注册为该对象的观察回调的函数的引用。

换句话说,这是行不通的:

代码语言:javascript
复制
(function() {
    var obj = { prop: "a" };

    Object.observe(obj, function(changes) {
        console.log(changes);
    });
    
    obj.prop = "b";

    Object.deliverChangeRecords(function(changes) {
        console.log(changes);
    });

    console.log("End of execution");
})(); // Meh, we're notified of changes here, which isn't what we wanted

而这将:

代码语言:javascript
复制
(function() {
    var obj = { prop: "a" },

        callback = function(changes) {
            console.log(changes);
        };
    
    Object.observe(obj, callback)

    obj.prop = "b";

    Object.deliverChangeRecords(callback); // Notified of changes here, synchronously: yay!

    console.log("End of execution");
})();

这是因为在内部,为对象调用Object.observe(obj, callback) obj会将传递的callback函数添加到obj的观察回调列表中(在规范中称为[[ChangeObservers]] )。每个回调都只对特定类型的更改(第三个Object.observe()参数)执行,如果没有传递参数,则执行所有默认的回调。(这是一个重要的细节,因为这意味着如果您想使用自定义的变更type,则需要显式地将其传递给Object.observe()__的第三个参数,否则不会收到任何此类更改的通知。)

此外,每个挂起的更改都将在内部添加到每个匹配的观察回调队列中。这意味着每个观察回调都有自己的一组挂起的更改。

这正是Object.deliverChangeRecords(callback)的作用所在:它接受callback的所有挂起的更改,并通过传递所有这些更改来执行回调。

这就解释了为什么deliverChangeRecords()只需要一个参数,即回调。如下面的示例所示,向deliverChangeRecords()传递回调将执行该回调,并包含其所有挂起的更改,包括来自多个对象的更改。这与回调的一般行为是一致的,可能是异步调用还是通过deliverChangeRecords()调用。

代码语言:javascript
复制
(function() {
    var obj1 = { prop1: "a" },
        obj2 = { prop2: "a" },

        commonCallback = function(changes) {
            console.log(changes);
        };
    
    Object.observe(obj1, commonCallback);
    Object.observe(obj2, commonCallback);

    obj1.prop1 = "b";
    obj2.prop2 = "b";

    Object.deliverChangeRecords(commonCallback); // Notified of the changes to both obj1.prop1 and obj2.prop2
})();

此外,规范中还提供了很好的使用实例

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27119307

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档