如果我使用以下超时解决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。 Crowder给出了一个令人惊奇的答案,很明显,这就是我需要对代码进行的更改:
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);
})
最佳答案
但是如果我立即解决延期而没有超时,如下所示...
在已解决的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的promise / deferreds设计。)回调访问值为
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
上施加至少4ms的延迟)回调,尽管不如HTML5规范中要求的那样一致)。哪个是对的?这完全是一个见解。从主观上来说,对我而言,语义应该胜出:可能是异步的回调应该始终是异步的-如果他们做出了这样的选择,您的代码就不会遇到问题,因为回调总是在赋值之后发生至
myObj
完成。但是聪明的jQuery开发人员做出了另一种选择,这是他们的正确选择。 :-)
关于javascript - “return deferred.promise(this)”返回未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26026506/