我想了解Object.getNotifier(object).performChange
。从概念上讲,我理解它是专门用于定义"宏"或更高级别的变化。来自example everyone seems to refer to:
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
的匿名函数有什么不同,而不是作为回调?换句话说,它与以下内容有何不同:
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
可能会返回一个对象,然后将其作为通知发布,如:
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
了,但是,这是否不是糖,或者它之间是否有功能差异,只是自己进行更改并发出通知?< / p>
答案 0 :(得分:5)
我想为这个问题提供一个明确的答案,我也问自己,所以我看了Object.observe spec。
以下是您需要了解Object.getNotifier(obj).performChange(changeType, changeFn)
的内容:
changeFn
changeFn
正在运行时,它故意不通知任何观察者obj
changeFn
返回一个对象:obj
将通过该对象自己的属性通知观察员要亲眼看看,%NotifierPrototype%.performChange(changeType, changeFn)
是您在规范中寻找的内容。
应用于您的示例,这意味着这两个导致完全相同的结果,同时做一些不同的事情:
示例1:
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:
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中显式调用notify()
得到的对象相同:{ object: Object, type: Thingy.INCREMENT, increment: amount }
< / LI>
这两个示例应涵盖您希望使用performChange()
的大多数情况,以及如何使用它。我会继续潜水,因为这种野兽的行为非常有趣。
观察者以异步方式执行。这意味着上面示例中increment()
函数内发生的所有内容实际上都会在increment()
执行完后向观察者报告 - 并且只有这样。
换句话说,所有这些:
performChange()
performChange()
的回调notify()
只有在increment()
完成运行后才会通知相应的观察者。
如果您需要了解increment()
执行期间的待处理更改(待处理的更改=将在increment()
结束时向观察员报告的所有更改,但是避难所&#但是,还有一个解决方案:Object.deliverChangeRecords(callback)
。
请注意,callback
需要是对您之前已注册为该对象的观察回调的函数的引用。
换句话说,这不会起作用:
(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
&#13;
虽然这会:
(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");
})();
&#13;
原因在于,在内部,为对象Object.observe(obj, callback)
调用obj
会将传递的callback
函数添加到obj
的观察回调列表中(在规范中称为[[ChangeObservers]]
)。这些回调中的每一个都只会针对特定类型的更改(第三个Object.observe()
参数)执行,如果没有传递参数,则所有默认值。 (这是一个重要的细节,因为这意味着如果您想使用自定义的type
更改,则需要明确将其传递给Object.observe()
&n;第三个参数,否则您不会收到有关该类型任何更改的通知。)
此外,每个待处理的更改都将在内部添加到每个匹配的观察回调队列中。这意味着每个观察回调都有自己的待定更改集。
这正是Object.deliverChangeRecords(callback)
的用途:它会对callback
进行所有挂起的更改,并通过将所有这些更改传递给该回调来执行。
这解释了为什么deliverChangeRecords()
只需要一个参数,即回调的参数。如下面的示例所示,将回调传递给deliverChangeRecords()
将使用所有其挂起的更改(包括来自多个对象的更改)执行该回调。这与回调的一般行为一致,可能是异步调用或通过deliverChangeRecords()
调用。
(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
})();
&#13;
此外,规范中还提供了好的 usage examples。
答案 1 :(得分:4)
经过一个小时的大量测试后,我终于明白了。我有同样的问题(什么是performChange
?),也是同样的想法,只是把它关闭并打电话
this.a += amount;
this.b += amount;
然而:notifier.performChange
的观点是观察者不会观察到每一个变化。
我正在测试它:
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);
它应该返回以下控制台输出:
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