jQuery的推迟和承诺 – .then()与.done()

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

任何人都可以请赐教正确的用法?

非常感谢

附加到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()

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

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

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

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

所以这取决于你自己该做什么…你关心它是否成功或失败了吗?

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

添加处理程序,以便在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); } 

实际上有一个非常关键的区别,因为jQuery的Deferreds是为了实现Promise(而jQuery3.0实际上是试图把它们引入规范)。

完成/之后的关键区别在于

  • .done()不管你做什么或返回什么,ALWAYS都会返回与之前相同的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做日志记录,而不是。 这是因为console.log函数实际上不会返回任何东西。 如果你传递了一个函数,那么返回什么呢?

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

这将记录:

未定义

发生了什么? 当我使用.then并传递了一个函数,它没有返回任何东西,它隐含的结果是“未定义”…这当然返回一个Promise [undefined]到下一个然后方法,记录未定义。 所以我们开始的原始价值基本上已经丧失了。

.then()是一个函数组合形式:每一步的结果在下一步中被用作函数的参数。 这就是为什么.done最好被认为是一个“tap” – 它实际上并不是构图的一部分,只是在某个步骤中偷偷地看着这个值,然后运行一个函数,但是并没有真正改变任何方式的组成。

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

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()取7作为a的值,取undefinedb的值,所以第二个then()用参数NaN返回一个新的promise,最后done()打印NaN作为结果。

那是我的答案。

 var deff = $.Deferred(); deff.then(function(){ alert('ok'); var deff = $.Deferred(); setTimeout(function(){ deff.resolve() }, 1000) return deff; }).then(function () { alert('ok2') }) deff.resolve() 

这是独特的功能。 它可以防止回调地狱。

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

实际上,如果你不打算附加更多的步骤来承诺,你应该使用.done() 。 欲了解更多细节,请看为什么承诺需要完成