.then()
和.done()
成功回调之间的区别。我知道Eric Hynds提到.done()
和.success()
映射到相同的功能,但是我猜.then()
也是这样,因为所有回调都在成功完成操作后调用。 有人可以启发我正确使用吗?
#1 楼
解决延迟问题后,将触发done()
附带的回调。 在jQuery 1.8之前,
fail()
只是语法糖:promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )
从1.8版本开始,
then()
是then()
的别名并返回新的Promise,请参见此处以获取有关pipe()
的更多信息。它们分别是pipe()
和success()
的简单别名:带有应在1.8.1中修复的版本1.8中的字符串:评论
然后重新履行诺言是我缺少的关键。我不明白为什么像$ .get(....)。done(function(data1){return $ .get(...)})。done(function(data2){...})这样的链由于未定义data2而失败;当我将完成更改为后来起作用时,因为我真的很想将promise放在一起,而不是将更多的处理程序附加到原始promise。
–wrschneider
15年3月27日在14:46
jQuery 3.0是第一个符合Promises / A +和ES2015规范的版本。
– Flimm
16年8月19日在16:58
我仍然不明白为什么我要在另一个上使用一个。如果我进行了ajax调用,而我需要等到该调用完全完成(这意味着从服务器返回响应)之后再调用另一个ajax调用,我应该使用done还是then?为什么?
–CodingYoshi
18/12/19在1:51
@CodingYoshi签出我的答案以最终回答该问题(使用.then())。
– Robert Siemer
4月1日7:04
#2 楼
返回结果的处理方式也不同(称为链接,done
不链接,而then
生成调用链)promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return 123;
}).then(function (x){
console.log(x);
}).then(function (x){
console.log(x)
})
以下结果将被记录:
abc
123
undefined
,而
promise.done(function (x) { // Suppose promise returns "abc"
console.log(x);
return 123;
}).done(function (x){
console.log(x);
}).done(function (x){
console.log(x)
})
将得到以下内容:
abc
abc
abc
----------更新:
顺便说一句。我忘了提一下,如果您返回Promise而不是原子类型值,则外部诺言将等到内部诺言得到解决:
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return $http.get('/some/data').then(function (result) {
console.log(result); // suppose result === "xyz"
return result;
});
}).then(function (result){
console.log(result); // result === xyz
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
这样变得非常简单组成并行或顺序异步操作,例如:
// Parallel http requests
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
var promise1 = $http.get('/some/data?value=xyz').then(function (result) {
console.log(result); // suppose result === "xyz"
return result;
});
var promise2 = $http.get('/some/data?value=uvm').then(function (result) {
console.log(result); // suppose result === "uvm"
return result;
});
return promise1.then(function (result1) {
return promise2.then(function (result2) {
return { result1: result1, result2: result2; }
});
});
}).then(function (result){
console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
上面的代码并行发出两个http请求,从而使请求尽快完成,而下面的那些http请求正在按顺序运行,从而减少服务器负载
// Sequential http requests
promise.then(function (x) { // Suppose promise returns "abc"
console.log(x);
return $http.get('/some/data?value=xyz').then(function (result1) {
console.log(result1); // suppose result1 === "xyz"
return $http.get('/some/data?value=uvm').then(function (result2) {
console.log(result2); // suppose result2 === "uvm"
return { result1: result1, result2: result2; };
});
});
}).then(function (result){
console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
console.log(und) // und === undefined, because of absence of return statement in above then
})
评论
+1表示已完成的操作不会对结果产生任何影响,然后更改结果。其他imo错过了巨大的机会。
–假名
13年5月14日在17:54
可能值得一提的是,它适用于什么版本的jQuery,因为then的行为在1.8中已更改
–bradley.ayers
13年5月30日在0:15
+1直达目标。如果有人想查看混合完成的链然后调用结果,我创建了一个可运行的示例。
– Michael Kropat
2014年2月4日在20:34
上面的示例还强调了“完成”对最初创建的原始承诺对象有效,但“然后”返回了新的承诺。
–普拉克·坎蒂·巴塔奇亚里(Pulak Kanti Bhattacharyya)
2014年8月2日在5:23
这适用于jQuery 1.8+。旧版本的行为就像完成的示例一样。然后更改为以1.8之前的版本进行管道传输,以获取1.8+的行为。
– David Harkness
14年8月14日,0:56
#3 楼
.done()
只有一个回调,它是成功回调.then()
只有成功和失败回调,.fail()
只有一个失败回调,所以它由您决定,您必须做什么...是否在乎它是否成功?
评论
您没有提及“然后”产生呼叫链。参见Lu4的答案。
–寡核苷酸
13-10-30在22:02
您的答案是从2011年开始...如今,它们的返回值使then()与done()非常不同。由于then()通常仅在成功回调中被调用,因此您的观点是一个细节而不是要记住/知道的主要事情。 (无法说出jQuery 3.0之前的情况。)
– Robert Siemer
3月31日15:22
#4 楼
deferred.done()添加仅在解析Deferred后才调用的处理程序。您可以添加多个要调用的回调。 > deferred.then()
添加要解析,拒绝或仍在进行Deferred时调用的处理程序。
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);
function doneCallback(result) {
console.log('Result 1 ' + result);
}
评论
您的帖子不清楚如果没有提供失败回调,那么行为将如何-即根本没有捕获失败案例
– B M
17年12月8日在16:16
失败案例会引发程序顶层可能捕获的异常。您还可以在JavaScript控制台中看到异常。
–David Spector
19年1月20日在21:07
#5 楼
实际上,有一个非常关键的区别,就jQuery的Deferreds而言,它是Promises的实现(而jQuery3.0实际上是试图将它们纳入规范)。done / then之间的主要区别在于, >
.done()
始终返回与开始时相同的Promise /包装值,无论您做什么或返回什么。 .then()
从jQuery转换为原生ES2015 Promises,负责控制Promise的功能。承诺链,如果该链处于“解决”状态,它将向函数传递值...但是该函数的结果不会影响链本身。const doneWrap = fn => x => { fn(x); return x };
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(doneWrap(console.log.bind(console)));
$.Deferred().resolve(5)
.done(x => x + 1)
.done(console.log.bind(console));
这些都将记录5,而不是6。
请注意,我使用done和doneWrap进行日志记录,而不是.then。那是因为console.log函数实际上不返回任何东西。如果您传递.then函数不返回任何内容会发生什么呢?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
将记录: />发生了什么事?当我使用.then并将其传递给任何不返回任何函数的函数时,它的隐式结果是“未定义” ...当然,该结果当然将Promise [undefined]返回给下一个then方法,该方法记录了未定义。因此,我们开始时使用的原始值基本上已经丢失。这就是为什么.done最好被认为是“敲击”的原因->它实际上不是组成部分,只是在某个步骤中偷偷看值并在该值上运行函数的东西,但实际上并没有改变以任何方式组成。
这是一个非常根本的差异,并且很可能有一个很好的理由,为什么本机Promises本身没有实现.done方法。我们无需深入探讨为什么没有.fail方法,因为这更加复杂(即,.fail / .catch不是.done / .then的镜像。.->。catch中返回裸值的函数不会像传递给.the的那些人一样拒绝了“ stay”,然后他们解决了!)
#6 楼
then()
始终表示在任何情况下都将调用它。但是传递的参数在不同的jQuery版本中是不同的。在jQuery 1.8之前,
then()
等于done().fail()
。并且所有回调函数共享相同的参数。 但是从jQuery 1.8开始,
then()
返回一个新的promise,并且如果它返回一个值,它将被传递到下一个回调函数中。示例: var defer = jQuery.Deferred();
defer.done(function(a, b){
return a + b;
}).done(function( result ) {
console.log("result = " + result);
}).then(function( a, b ) {
return a + b;
}).done(function( result ) {
console.log("result = " + result);
}).then(function( a, b ) {
return a + b;
}).done(function( result ) {
console.log("result = " + result);
});
defer.resolve( 3, 4 );
在jQuery 1.8之前,答案应该是
result = 3
result = 3
result = 3
所有
result
都需要3。并且then()
函数始终将相同的延迟对象传递给下一个函数。但是从jQuery 1.8开始,结果应该是:
result = 3
result = 7
result = NaN
因为第一个
then()
函数返回一个新的promise,所以将值7(这是将传递的唯一参数)传递给下一个done()
,因此第二个done()
写入result = 7
。第二个then()
将7用作a
的值,并将undefined
用作b
的值,因此第二个then()
返回带有参数NaN的新promise,最后一个done()
打印NaN作为其结果。评论
“ then()始终意味着在任何情况下都将调用它” –不正确。如果Promise内部发生错误,则永远不会调用then()。
–David Spector
19年1月20日在21:08
有趣的方面是jQuery.Deferred()可以接收多个值,并将其正确地传递到第一个.then()。—有点奇怪,但是任何随后的.then()都不能这样做。 (通过return选择的接口只能返回一个值。)JavaScript的本机Promise不会这样做。 (老实说,这是更一致的。)
– Robert Siemer
4月1日1:52
#7 楼
响应中有一个非常简单的思维导图,很难在其他答案中找到:承诺#8 楼
jQuery 3.0还有一个重要的区别,它很容易导致意外行为,并且在以前的答案中没有提及: let d = $.Deferred();
d.done(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
这将输出: br />
done()
then()
输出现在是:同步方式,而传递给
var d = $.Deferred();
d.then(() => console.log('then'));
d.resolve();
console.log('now');
的任何参数均异步调用。 这与升级版本中提到的同步调用两个回调的jQuery早期版本不同:
Deferred .then()回调始终被异步调用。
以前,如果将.then()回调添加到已经被解析或拒绝的Deferred中,则该回调将立即运行和
同步。
评论
谢谢。这个答案解释了我所看到的行为。我正在使用then()。我的测试失败了,因为测试结束后,回调被称为异步。使用done()回调被同步调用,满足测试期望,测试通过。
–尚达什坚
6月18日22:25
#9 楼
仅使用.then()
这些是
.done()
的缺点不能链接
阻止
resolve()
调用(所有.done()
处理程序将resolve()
可能会从已注册的.done()
处理程序中获取异常(!).done()
中的异常会杀死延迟的内容:我进一步认为,
.done()
处理程序将被静默跳过我暂时认为
.then(oneArgOnly)
始终需要.catch()
,因此不会有任何异常被静默忽略,但这不再是真的:unhandledrejection
事件在控制台上记录未处理的.then()
异常(默认情况下)。很合理!完全没有理由完全使用.done()
。在.done()
点被称为同步记录为1、3、5、7
在脚本掉入底部之前记录
>
resolve()
中的异常会影响.done()
调用方通过捕获
resolve()
捕获例外会破坏进一步的
resolve()
分辨率的承诺/>
8和10未记录!
.done()
没有这些问题在线程变为空闲后记录为2、4、6、9、11不能正确捕获:由于
.then()
的同步模式,错误要么在unhandledrejection
的点(可能是库代码!)抛出,要么在.done()
调用中抛出,如果延期已经解决。 .done()
.resolve()
评论
有几件事情:1)我明白您在说什么,如果先前的完成有异常,则不会执行完成。但是为什么会默默地忽略它,我的意思是发生了异常,所以为什么您说它是默默的。 2)我鄙视Deferred对象,因为它的API做得非常非常差。这太复杂和令人困惑。您的代码在这里既无助于证明您的观点,又对您要证明的内容具有不必要的复杂性。 3)为什么在索引2,索引4,索引6和索引6之前完成索引2?
–CodingYoshi
4月11日14:04
不好意思,您绝对应该投票。至于您对异常的评论,通常就是异常的工作方式:一旦引发,它之后的代码将不被执行。加上jQuery文档指出,只有在延迟解决后,它才会执行。
–CodingYoshi
4月13日下午1:00
@CodingYoshi这里的情况有所不同:我只是在谈论已解决的承诺/延期。我并不是在抱怨没有成功处理程序的其余部分,这很正常。但是我认为没有理由不称呼一个完全不同的成功承诺者。所有.then()都会被调用,无论是否引发异常(在那些处理程序中)。但是添加/剩余的.done()会中断。
– Robert Siemer
4月13日下午5:48
@CodingYoshi,如果可以说的话,我的回答大大改善了。代码和文字。
– Robert Siemer
4月13日13:00
#10 楼
.done()
终止了promise链,确保没有其他东西可以附加进一步的步骤。这意味着jQuery Promise实现可以抛出任何未处理的异常,因为没有人可以使用.fail()
来处理它。实际上,如果您不打算对Promise附加更多步骤,则应该使用
.done()
。有关更多详细信息,请参见为什么需要兑现承诺评论
警告!这个答案对于几种promise实现是正确的,但对于jQuery.done()没有终止作用的jQuery而言,它不是正确的。该文档说:“由于deferred.done()返回延迟的对象,因此可以将延迟对象的其他方法链接到该对象,包括其他.done()方法。”没有提到.fail(),但是,可以,也可以将其链接起来。
–漫游者1888
2014年10月30日16:23
我不好,没有检查jQuery
–gleb bahmutov
2014年10月30日在16:42
@glebbahmutov-也许您应该删除此答案,以免其他人感到困惑?只是一个友好的建议:)
–安德烈
2015年10月13日,0:57
请不要删除答案,这也可以帮助人们消除误解。
–梅利莎
2015年12月21日,下午3:17
评论
请注意所有人,2016年6月发布的JQuery 3.0是第一个符合Promises / A +和ES2015 Promises规范的版本。在此之前的实现与应有的承诺不兼容。我更新了答案,并提出了有关何时使用的改进建议。