jQuery延迟并承诺-.then()vs .done()

问题描述 投票:459回答:9

我一直在阅读有关jQuery的递归和诺言,但我看不出使用.then().done()进行成功的回调之间的区别。我知道Eric Hynds提到.done().success()映射到相同的功能,但是我猜想.then()也是这样,因为所有回调都在成功完成操作时被调用。

任何人都可以启发我正确使用吗?

jquery promise jquery-deferred
9个回答
562
投票

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

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

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

从1.8开始,then()pipe()的别名,并返回新的Promise,有关here的更多信息,请参见pipe()

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()相同。


405
投票

处理返回结果的方式也有所不同(称为链接,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
})

56
投票

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

.then()同时具有成功和失败回调

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

因此取决于您,您必须执行的操作...您是否在乎它是否成功?


15
投票

deferred.done()

仅将处理程序添加为仅在延迟解决后才被调用。您可以添加多个要调用的回调。

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

添加要被调用的处理程序当延迟,解析,拒绝或仍在进行中时

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

9
投票

实际上,就jQuery的Deferreds而言,它是Promises的实现(实际上jQuery3.0试图将它们纳入规范),实际上存在一个非常关键的区别。

完成/然后之间的主要区别是

  • .done()始终返回与开始时相同的Promise /包装值,无论您执行什么操作或返回什么。
  • .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函数实际上不返回任何东西。如果您传递.then函数不返回任何内容,会发生什么?

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(console.log.bind(console))
       .then(console.log.bind(console));

将记录:

5

未定义

发生了什么事?当我使用.then并将其传递给一个不返回任何内容的函数时,它的隐式结果是“未定义” ...当然,该结果将Promise [undefined]返回给下一个then方法,该方法记录了未定义。因此,我们最初使用的原始值基本上已经丢失。

.then()本质上是函数组合的一种形式:每个步骤的结果都用作下一步中该函数的参数。这就是为什么.done最好被认为是“敲击”的原因->它实际上不是组合的一部分,而只是在某个步骤中偷偷看了一下值并在该值下运行了函数,但实际上并没有改变以任何方式组成。

这是一个非常根本的区别,并且很可能有一个很好的理由,为什么本地Promises本身没有实现.done方法。我们无需深入探讨为什么没有.fail方法,因为这更加复杂(即,.fail / .catch不是.done / .then的镜像,.catch中返回裸值的函数不会就像传递给.then的那些人一样,“ stay”被拒绝了,他们解决了!


5
投票

then()始终表示在任何情况下都将调用它。但是传递的参数在不同的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()的任何参数都将异步调用。 

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

实际上,如果您不打算在承诺上附加更多步骤,则应使用.done()。有关更多详细信息,请参见why promises need to be done


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

实际上,如果您不打算在承诺上附加更多步骤,则应使用.done()。有关更多详细信息,请参见why promises need to be done

© www.soinside.com 2019 - 2024. All rights reserved.