Javascript 观察同步回调
我一直在用ChromeV36的Object.observe做实验。我最初的意图是在我的模型中将其用于业务逻辑,但异步行为似乎使其不可能。我将此归结为以下示例:Javascript 观察同步回调,javascript,angularjs,object.observe,Javascript,Angularjs,Object.observe,我一直在用ChromeV36的Object.observe做实验。我最初的意图是在我的模型中将其用于业务逻辑,但异步行为似乎使其不可能。我将此归结为以下示例: function Person(name) { this.name = name; this.someOtherProperty = null; this.watch = function() { var self = this; Object.observe(this, functi
function Person(name) {
this.name = name;
this.someOtherProperty = null;
this.watch = function()
{
var self = this;
Object.observe(this, function(changes){
for(var i = 0; i < changes.length; i++)
{
if(changes[i].name == "name")
{
self.someOtherProperty = changes[i].newValue;
console.log("Property Changed");
}
}
});
}
}
$(function () {
var p = new Person("Alice");
p.watch();
p.name = "Bob";
$("#output").text("Output: "+ p.someOtherProperty);
console.log("Output");
});
职能人员(姓名){
this.name=名称;
this.someOtherProperty=null;
this.watch=函数()
{
var self=这个;
对象。观察(此、功能(更改){
对于(变量i=0;i
链接,使用jQuery
我的问题是在“属性更改”之前调用“输出”。有没有什么方法可以使Object.observesynchronous,或者我应该用一种更好的方法?(我用的是AngularJS,顺便说一句)
这里的问题不是向DOM添加文本,也不是向控制台输出。当name
发生更改时,我的业务逻辑要求我立即更新someotherproperty
,我更喜欢将此逻辑封装在我的模型中
显然,这只是一个示例,但我有依赖于即时执行的业务规则。
对象。请注意,
,“很遗憾”(阅读下一页),不执行同步任务。一旦“微任务”结束,它就会发送更改通知
这是可以解释的
多年的web平台经验告诉我们,同步方法是您尝试的第一件事,因为它最容易让您绞尽脑汁。问题是,它创建了一个从根本上讲是危险的处理模型。如果你在写代码,比如说,更新一个对象的属性,你不会真的想要一个更新该对象属性的情况,可能会邀请一些任意代码去做它想做的事情。当你在函数中间运行时,让你的假设失效是不理想的
因此,调用console.log(“Output”)
后,“微任务”结束,然后Object.observe
通知对象上的更改
拥有同步事件的经典方法是使用getter和setter:
Person.prototype.setName = function(name) {
this.name = name;
console.log("Name Changed");
};
p.setName("Bob");
当然,这将迫使您为要查看的每个属性创建getter和setter,并忘记删除和添加新属性时发生的事件。使用
对象是没有意义的。请同步观察行为。它必须阻塞线程并等待某些内容发生更改
您应该将回调传递给watch
函数,以便在发生更改时执行该函数:
this.watch = function (callback) {
var self = this;
Object.observe(this, function (changes) {
changes.forEach(function (change) {
if (change.name === 'name') {
self.someOtherProperty = change.newValue;
console.log("Property Changed");
callback();
}
});
});
}
$(function () {
var p = new Person("Alice");
p.watch(function () {
// !!!!! OF COURCE YOU SHOULD NEVER DO IT LIKE THIS IN ANGULAR !!!! //
$("#output").text("Output: " + p.someOtherProperty);
console.log("Output");
});
p.name = "Bob";
});
顺便说一句,如果您使用的是Angular(通过您的代码和fiddle,这一点并不明显),那么您不应该关心在观察到的更改发生时执行任何代码。只要将代码包装在$scope.$apply()
中,Angular就会负责更新视图等
例如:
输出:{p.someOtherProperty}
.controller('someCtrl',函数($scope,Person){
$scope.p=新人('Alice');
$scope.p.watch();
$scope.p.name='Bob';
});
应用程序工厂('Person',函数($rootScope){
返回功能人员(姓名){
var self=这个;
self.name=名称;
self.someOtherProperty=null;
this.watch=函数(){
观察对象(自身、功能(变化){
$rootScope.$apply(函数(){
更改。forEach(函数(更改){
控制台日志(更改);
如果(change.name=='name'){
self.someOtherProperty=self.name;
}
});
});
});
};
};
});
另请参见此
更好的是,请参见此
基本上,使用O.O
而不是Angular的脏检查的优点是节省了$$watchers
,因此$digest
周期更快,成本更低。
Angular也会在ES6出现时使用此机制(O.O
)。正如您所说,observe是不同步的。但是你可以让watch回拨并在那里更新“someOtherProperty”。像这样
$(function () {
var p = new Person("Alice");
p.watch(function(){
$("#output").text("Output: "+ p.someOtherProperty);
});
p.name = "Bob";
console.log("Output");
});
你真正想要的是什么,我想你知道这是预期的行为。@ExpertSystem我想他的意思是,有时候,如果O.O
是同步的,它会很有用。但这是一个经验问题,因为同步解决方案会导致许多其他潜在问题。这也是为什么我们使用了MutationObserver
而不是MutationEvents
@TroelsLarsen,MaxArt:我以为你在谈论O.O
本身的(同步/异步)性质。似乎您正在讨论调用O.O
侦听器回调的方法。所以,我们现在在同一页上,我同意这两个观点:)@ExpertSystem:好的,我想我现在明白你的意思了。我想克里斯汀森是对的。我需要以某种方式使用getter和setter。@TroelsLarsen:这取决于您试图对代码做什么。如果您只想更新视图,则不需要getter/setter(感谢Angular)。请看,我回答中的最后一个示例/演示。@ExpertSystem:回顾过去,我不应该以视图为例。这仅用于模型内的业务逻辑。因此,如果PropertyA发生变化,PropertyB将获得一个新值。我将angular抽象为angular,因为我(目前)在模型中不需要DependencyInjection。类似地,我不想知道任何关于角度范围或类似的东西。我不介意为ge编写(生成)代码
$(function () {
var p = new Person("Alice");
p.watch(function(){
$("#output").text("Output: "+ p.someOtherProperty);
});
p.name = "Bob";
console.log("Output");
});