我一直在阅读jQuery的延迟和承诺,我看不出使用.then()和.done()成功回调之间的区别。我知道Eric Hynds提到.done()和.success()映射到相同的功能,但我猜.then()也是如此,因为所有的回调都是在成功操作完成时调用的。
有人能告诉我正确的用法吗?
我一直在阅读jQuery的延迟和承诺,我看不出使用.then()和.done()成功回调之间的区别。我知道Eric Hynds提到.done()和.success()映射到相同的功能,但我猜.then()也是如此,因为所有的回调都是在成功操作完成时调用的。
有人能告诉我正确的用法吗?
当前回答
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
所有结果花费3。然后()函数总是将相同的延迟对象传递给下一个函数。
但是从jQuery 1.8开始,结果应该是:
result = 3
result = 7
result = NaN
因为第一个then()函数返回一个新的promise,值7(这是唯一要传递的参数)被传递给下一个done(),所以第二个done()将result = 7。第二个then()将7作为a的值,并将undefined作为b的值,因此第二个then()返回一个带有参数NaN的新承诺,最后一个done()打印NaN作为其结果。
其他回答
deferred.done ()
添加仅在Deferred被解析时调用的处理程序。您可以添加多个回调被调用。
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);
deferred.then ()
当Deferred被解析、拒绝或仍在进行时,添加要调用的处理程序。
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);
}
除了以上的答案:
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后面
.done()只有一个回调,它是成功回调
.then()有success和fail两个回调函数
.fail()只有一个失败回调
所以你该怎么做就怎么做了…你在乎成功还是失败吗?
在回答中有一个非常简单的心理映射,在其他答案中很难找到:
done实现了蓝鸟承诺中的tap 然后实现然后在ES6承诺
实际上有一个非常关键的区别,因为jQuery的deferred是承诺的实现(query3.0实际上试图将它们纳入规范)。
完成/然后之间的关键区别是
.done()总是返回与开始时相同的Promise/wrapped值,无论你做什么或你返回什么。 .then()总是返回一个NEW 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函数实际上并不返回任何东西。如果你传递。then一个不返回任何东西的函数会发生什么?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
这将记录:
5 未定义的
发生了什么事?当我使用.then并传递给它一个不返回任何东西的函数时,它的隐式结果是“undefined”…它当然会返回一个Promise[undefined]给next then方法,该方法的日志为undefined。所以我们开始时的初始值基本失去了。
.then()本质上是一种函数组合形式:每一步的结果都被用作下一步函数的实参。这就是为什么.done最好被认为是一个“tap”->,它实际上不是组合的一部分,只是在某一步偷偷查看值并在该值上运行函数,但实际上并不以任何方式改变组合。
这是一个非常基本的区别,可能有一个很好的原因,为什么本机promise没有实现自己的.done方法。我们不需要讨论为什么没有.fail方法,因为它更复杂(即.fail/。catch不是.done/的镜像。然后- .catch中返回裸值的>函数不会像传递给.catch的函数那样被拒绝,然后它们会被解决!)