如果我使用超时解决3秒后的延迟,则以下代码有效...
var myConstructor = function(){
var deferred = $.Deferred();
this.message = "yo";
setTimeout(function(){
deferred.resolve();
}, 3000);
return deferred.promise(this);
}
var myObj = new myConstructor().done(function(){
console.log(myObj.message);
})
但是,如果我立即解决延迟而没有超时,如下所示......
var myConstructor = function(){
var deferred = $.Deferred();
this.message = "yo";
deferred.resolve();
return deferred.promise(this);
}
var myObj = new myConstructor().done(function(){
console.log(myObj.message);
})
...然后我得到以下错误:“无法在console.log行上读取未定义的属性'消息'。为什么立即解析延迟导致myObj未定义?
编辑:
在我评论@ T.J之后。克劳德的惊人答案,很明显,这是我需要对代码做出的改变:
var myConstructor = function(){
var deferred = $.Deferred();
this.message = "yo";
deferred.resolve();
return deferred.promise(this);
}
var myObj = new myConstructor();
myObj.done(function(){
console.log(myObj.message);
})
答案 0 :(得分:4)
但是,如果我立即解决延迟而没有超时,如下所示......
当您在已经已解决的done
上致电Deferred
时,同步会调用其回调。在您的情况下,这意味着在赋值操作完成之前回调被称为,因此myObj
没有值(尚未)。
让我们打破这段代码:
var myObj = new myConstructor().done(function(){
console.log(myObj.message);
});
...当你(不使用setTimeout
时)发生的事情:
myObj
的变量,其值为undefined
。new myConstructor()
,其中:
myConstructor.prototype
myConstructor
,this
引用该对象done
,传入匿名函数。
Deferred
已经已经解决,done
会立即调用回调而不是等待。 (我恰好是那些不同意这种设计选择*的人,但这就是jQuery的承诺/推迟的设计。) myObj
,其值为undefined
,因此会抛出异常done
返回,myObj
获取其返回值。但是当你使用setTimeout
:
myObj
的变量,其值为undefined
。new myConstructor()
,其中:
myConstructor.prototype
myConstructor
,this
引用该对象done
,传入匿名函数。由于Deferred
尚未(尚未)解析,因此不会调用回调。done
返回,myObj
获取其返回值。Deferred
:
myObj
,其值为步骤5并成功使用。 *“设计选择” - 如果done
已经解决,则Deferred
同步调用回调是一种设计选择。它以性能换取语义。基本上,jQuery开发人员有两个选择:
同步调用回调,意味着语义混乱(有时它被同步调用,其他时间是异步调用),或者
即使状态已知(通过setTimeout(..., 0)
或类似),也会异步调用回调,这意味着保留了语义(回调始终异步),但性能可能会受到影响(浏览器有时会在setTimeout
回调上施加最小4毫秒的延迟,但不像HTML5规范那样一致。)
哪个是对的?这完全是一个意见问题。主观上,对于 me ,语义应该胜利:可能异步的回调应该总是是异步的 - 如果他们做出了这个选择,你的代码不会遇到问题,因为在分配给myObj
之后,回调总是会发生。但是jQuery开发人员,他们是一个聪明的人,做出了另一个选择,这是他们的权利。 : - )
答案 1 :(得分:1)
var myConstructor = function(){
var deferred = $.Deferred();
this.message = "yo";
deferred.resolveWith(this, [this.messgae]);
return deferred.promise();
}
var myObj = new myConstructor().done(function(){
console.log(this.message); // `yo`
$("body").append(this.message);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
修改
还可以resolve(this.message)
var myConstructor = function(){
var deferred = $.Deferred();
this.message = "yo";
deferred.resolve(this.message);
return deferred.promise();
}
var myObj = new myConstructor();
myObj.done(function(msg){
console.log(msg); // `yo`
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>