首页 文章

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

提问于
浏览
429

我看到使用 .then().done() 成功回调之间的区别 . 我知道Eric Hynds提到 .done().success() 映射到相同的功能,但我猜 .then() 也是如此,因为所有的回调都是在成功操作完成时调用的 .

任何人都可以请你告诉我正确的用法?

非常感谢

8 回答

  • 534

    解析延迟时,将触发附加到 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() 仅在通过调用 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() .

  • 6

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

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

    .then() 既有成功也有失败的回调

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

    所以取决于你必须做的事情......如果成功或失败,你会关心吗?

  • 4

    deferred.done()

    添加处理程序称为 only when Deferred is resolved . 您可以添加要调用的多个回调 .

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

    添加处理程序称为 when Deferred is resolved, rejected or still in progress .

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

    实际上存在一个相当重要的区别,因为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 . 所以我们开始的原始 Value 基本上已经失去了 .

    .then() 本质上是一种函数组合形式:每个步骤的结果用作下一步中函数的参数 . 那个's why .done is best thought of as a 887688 -> it'实际上并不是构图的一部分,只是在某一步骤中偷看某个值并在该值处运行函数,但实际上并没有以任何方式改变构图 .

    这是一个非常基本的区别,并且可能有一个很好的理由为什么本机Promise没有自己实现的.done方法 . 我们没有必须深入了解为什么没有.fail方法,因为它更复杂(即.fail / .catch不是.done / .then的镜像 - > .catch中的函数返回裸值不“停留”被拒绝,就像传递给那些人一样 . 然后,他们解决了!)

  • 50

    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的新promise,最后一个 done() 打印NaN作为结果 .

  • -5

    在响应中有一个非常简单的心理映射,在其他答案中有点难以找到:

  • 376

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

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

相关问题