我一直在阅读jQuery的延迟和承诺,我看不出使用.then()和.done()成功回调之间的区别。我知道Eric Hynds提到.done()和.success()映射到相同的功能,但我猜.then()也是如此,因为所有的回调都是在成功操作完成时调用的。

有人能告诉我正确的用法吗?


当前回答

.done()终止承诺链,确保没有其他步骤可以附加。这意味着jQuery承诺实现可以抛出任何未处理的异常,因为没有人可以使用.fail()处理它。

实际上,如果您不打算为承诺附加更多步骤,则应该使用.done()。要了解更多细节,请参阅为什么需要兑现承诺

其他回答

.done()只有一个回调,它是成功回调

.then()有success和fail两个回调函数

.fail()只有一个失败回调

所以你该怎么做就怎么做了…你在乎成功还是失败吗?

附加到done()的回调将在延迟被解决时被触发。当延迟被拒绝时,附加到fail()的回调将被触发。

在jQuery 1.8之前,then()只是语法糖:

promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )

从1.8开始,then()是pipe()的别名,并返回一个新的promise,有关pipe()的更多信息,请参阅这里。

success()和error()仅在调用ajax()返回的jqXHR对象上可用。它们分别是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()也是一样。

除了以上的答案:

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后面

实际上有一个非常关键的区别,因为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的函数那样被拒绝,然后它们会被解决!)

在处理返回结果的方式上也有区别(它被称为链接,done不链接,然后产生调用链)

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
})