我一直在阅读jQuery延迟和承诺,我看不出使用.then()
&和成功回调.done()
。我知道Eric Hynds提到.done()
和.success()
映射到相同的功能,但我猜测.then()
也是如此,因为所有回调都是在成功完成时调用的操作。
任何人都可以告诉我正确的使用方法吗?
答案 0 :(得分:551)
解决延迟时,将触发附加到done()
的回调。当延迟被拒绝时,将触发附加到fail()
的回调。
在jQuery 1.8之前,then()
只是语法糖:
promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )
从1.8开始,then()
是pipe()
的别名并返回新的承诺,有关pipe()
的更多信息,请参阅here。
success()
和error()
仅适用于jqXHR
调用返回的ajax()
对象。它们分别是done()
和fail()
的简单别名:
jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error
此外,done()
不限于单个回调,并将过滤掉非函数(尽管版本1.8中的字符串存在错误,应该在1.8.1中修复):
// this will add fn1 to 7 to the deferred's internal callback list
// (true, 56 and "omg" will be ignored)
promise.done( fn1, fn2, true, [ fn3, [ fn4, 56, fn5 ], "omg", fn6 ], fn7 );
同样适用于fail()
。
答案 1 :(得分:391)
处理返回结果的方式也有所不同(称为链接,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会等到内部的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
})
答案 2 :(得分:51)
.done()
只有一个回调,它是成功回调
.then()
同时有成功和失败的回调
.fail()
只有一个失败回调
所以取决于你必须做的事情......你关心它是否成功或是否失败了?
答案 3 :(得分:13)
添加处理程序仅在延迟解决时称为。您可以添加多个要回调的回调。
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);
function doneCallback(result) {
console.log('Result 1 ' + result);
}
你也可以这样写,
function ajaxCall() {
var url = 'http://jsonplaceholder.typicode.com/posts/1';
return $.ajax(url);
}
$.when(ajaxCall()).then(doneCallback, failCallback);
在延期解决,拒绝或仍在进行中时,将处理程序称为 。
var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).then(doneCallback, failCallback);
function doneCallback(result) {
console.log('Result ' + result);
}
function failCallback(result) {
console.log('Result ' + result);
}
答案 4 :(得分:8)
实际上存在一个相当重要的区别,因为jQuery的Deferreds是Promises的实现(并且jQuery3.0实际上试图将它们引入规范)。
完成/之后的关键区别是
.done()
总是返回它开头的相同Promise / wrapped值,无论你做什么或者你返回什么。 .then()
总是返回一个新的Promise,你负责根据你传递的函数控制Promise的内容。 从jQuery转换为本机ES2015 Promises,.done()
有点像围绕Promise链中的函数实现“tap”结构,因为如果链处于“resolve”状态,它将会是将值传递给函数...但该函数的结果不会影响链本身。
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函数实际上并没有返回任何内容。如果你通过,那会发生什么。然后一个不返回任何东西的函数?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
那将记录:
5
未定义
发生什么事了?当我使用.then并传递一个没有返回任何内容的函数时,它的隐式结果是“未定义”......当然,它将Promise [undefined]返回给下一个方法,该方法记录为undefined。所以我们开始的原始价值基本上已经失去了。
.then()
本质上是一种函数组合形式:每个步骤的结果用作下一步中函数的参数。这就是为什么.done最好被认为是“点击” - >它实际上并不是构图的一部分,只是在某个步骤中偷看某个值并在该值处运行函数,但实际上并没有以任何方式改变构图。
这是一个非常基本的区别,并且可能有一个很好的理由为什么本机Promise没有自己实现的.done方法。我们没有必须深入了解为什么没有.fail方法,因为它更复杂(即.fail / .catch不是.done / .then - > .catch中返回裸值的函数的镜像不要像那些传递给那些人那样“停留”。然后,他们会解决!)
答案 5 :(得分:4)
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()
将a
的值设为7,并将undefined
作为b
的值,因此第二个then()
将返回带有参数的新保证NaN和最后done()
打印NaN作为结果。
答案 6 :(得分:2)
.then()
这些是.done()
resolve()
调用(所有.done()
处理程序将同步执行)resolve()
可能会从注册的.done()
处理程序中获得异常(!).done()
中的异常会杀死延迟者:
.done()
处理程序将被静默跳过我暂时认为.then(oneArgOnly)
总是需要.catch()
,因此不会无声地忽略任何异常,但这不再是事实:unhandledrejection
事件记录了未处理的.then()
异常在控制台上(默认)。很合理!完全没有理由使用.done()
。
以下代码段揭示了这一点,
.done()
处理程序将在resolve()
点被称为同步处理程序
.done()
中的resolve()
呼叫者
resolve()
赶上来记录.done()
解决方案的承诺
.then()
没有这些问题
unhandledrejection
)顺便说一句,.done()
的异常无法正确捕获:由于.done()
的同步模式,错误要么在.resolve()
处抛出(可能是库代码) !)或在.done()
呼叫中,如果已解决延期问题,则附加罪魁祸首。
console.log('Start of script.');
let deferred = $.Deferred();
// deferred.resolve('Redemption.');
deferred.fail(() => console.log('fail()'));
deferred.catch(()=> console.log('catch()'));
deferred.done(() => console.log('1-done()'));
deferred.then(() => console.log('2-then()'));
deferred.done(() => console.log('3-done()'));
deferred.then(() =>{console.log('4-then()-throw');
throw 'thrown from 4-then()';});
deferred.done(() => console.log('5-done()'));
deferred.then(() => console.log('6-then()'));
deferred.done(() =>{console.log('7-done()-throw');
throw 'thrown from 7-done()';});
deferred.done(() => console.log('8-done()'));
deferred.then(() => console.log('9-then()'));
console.log('Resolving.');
try {
deferred.resolve('Solution.');
} catch(e) {
console.log(`Caught exception from handler
in resolve():`, e);
}
deferred.done(() => console.log('10-done()'));
deferred.then(() => console.log('11-then()'));
console.log('End of script.');
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"
></script>
答案 7 :(得分:1)
在回答中有一个非常简单的心理映射,在其他答案中有点难以找到:
tap
实施then
,如bluebird Promises
then
实施<div class="primary-colors">
<h3>Primary Colors</h3>
<div class="primary-range-container">
<input type="range" min="1" max="15" value ="5" class="primary-slider"><span class="value">0</span>
</div>
<hr>
<div class="color-container">
<div class="color primary-color-1"></div>
<div class="color primary-color-2"></div>
<div class="color primary-color-3"></div>
<div class="color primary-color-4"></div>
<div class="color primary-color-5"></div>
<div class="color primary-color-6"></div>
<div class="color primary-color-7"></div>
<div class="color primary-color-8"></div>
<div class="color primary-color-9"></div>
<div class="color primary-color-10"></div>
<div class="color primary-color-11"></div>
</div>
</div>
,如ES6 Promises
答案 8 :(得分:0)
自 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>
这将输出:
then
now
现在,在相同的代码段中将done()
替换为then()
:
var d = $.Deferred();
d.then(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
现在输出为:
now
then
因此,对于立即解决的延迟,传递给done()
的函数将始终以同步方式调用,而传递给then()
的任何参数均异步调用。
这与先前的jQuery版本不同,在jQuery中,两个回调都被同步调用,如upgrade guide中所述:
遵守Promises / A +要求的另一个行为更改是 延迟的.then()回调始终被异步调用。 以前,如果将.then()回调添加到Deferred中,则 已经解决或被拒绝,回调将立即运行, 同步。
答案 9 :(得分:0)
除了上面的答案:
.then 的真正威力在于能够以流畅的方式链接 ajax 调用,从而避免回调地狱。
例如:
$.getJSON( 'dataservice/General', {action:'getSessionUser'} )
.then( function( user ) {
console.log( user );
return $.getJSON( 'dataservice/Address', {action:'getFirstAddress'} );
})
.then( function( address ) {
console.log( address );
})
这里第二个 .then 跟随返回的 $.getJSON
答案 10 :(得分:-4)
.done()
终止了承诺链,确保没有其他任何东西可以附加进一步的步骤。这意味着jQuery promise实现可以抛出任何未处理的异常,因为没有人可以使用.fail()
来处理它。
实际上,如果您不打算在承诺中附加更多步骤,则应使用.done()
。有关详细信息,请参阅why promises need to be done