jQuery deferreds and promises - .then() vs .done()
我一直在阅读jquery延迟和承诺,我看不到使用
有人能告诉我正确的用法吗?
当延迟解决时,将触发附加到
在jquery 1.8之前,
1 2 3 | promise.then( doneCallback, failCallback ) // was equivalent to promise.done( doneCallback ).fail( failCallback ) |
截至1.8,
1 2 | jqXHR.done === jqXHR.success jqXHR.fail === jqXHR.error |
号
另外,
1 2 3 | // 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 ); |
同样适用于
在处理返回结果的方式上也存在差异(称为链接,
1 2 3 4 5 6 7 8 | 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) }) |
。
将记录以下结果:
1 2 3 | abc 123 undefined |
同时
1 2 3 4 5 6 7 8 | 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) }) |
。
将得到以下信息:
1 2 3 | abc abc abc |
。
-------更新:
顺便说一句,我忘了说,如果您返回一个承诺而不是原子类型值,那么外部承诺将一直等到内部承诺解决:
1 2 3 4 5 6 7 8 9 10 11 | 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 }) |
这样,组成并行或顺序异步操作变得非常简单,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // 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请求则按顺序运行,从而减少服务器负载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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 2 3 4 5 6 | var url = 'http://jsonplaceholder.typicode.com/posts/1'; $.ajax(url).done(doneCallback); function doneCallback(result) { console.log('Result 1 ' + result); } |
。
你也可以这样写,
1 2 3 4 5 6 | function ajaxCall() { var url = 'http://jsonplaceholder.typicode.com/posts/1'; return $.ajax(url); } $.when(ajaxCall()).then(doneCallback, failCallback); |
号延迟。然后())
添加在解决、拒绝或仍在进行延迟时要调用的处理程序。
1 2 3 4 5 6 7 8 9 10 | 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的延迟意味着承诺的实现(而jquery3.0实际上试图将它们引入规范)。
"完成/然后"之间的关键区别是
- 无论您做什么或返回什么,
.done() 始终返回与它开始时相同的承诺/包装值。 .then() 总是返回一个新的承诺,而您负责根据您传递给它的函数来控制该承诺的内容。
从jquery转换为原生的es2015 promises,
1 2 3 4 5 6 7 8 9 | 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函数实际上不返回任何内容。如果你通过了,会发生什么呢,那么一个不返回任何内容的函数?
1 2 3 4 | Promise.resolve(5) .then(doneWrap( x => x + 1)) .then(console.log.bind(console)) .then(console.log.bind(console)); |
号
这将记录:
5
undefined
号
发生什么事了?当我使用时。然后传递给它一个不返回任何内容的函数,它的隐式结果是"未定义"…当然,它向下一个then方法返回了一个promise[未定义],记录了未定义的。所以我们开始时的原值基本上是丢失的。
这是一个非常基本的区别,而且可能有一个很好的理由,为什么本地的承诺没有一个.done方法实现自己。我们不必解释为什么没有.fail方法,因为这更复杂(即,.fail/.catch不是.done/.then->functions in.catch中返回裸值的镜像,而不是像传递给的那样"保留"被拒绝。然后,它们就解决了!)
在jquery 1.8之前,
但从jquery 1.8开始,
让我们看看下面的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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之前,答案应该是
1 2 3 | result = 3 result = 3 result = 3 |
号
所有
但从jquery 1.8开始,结果应该是:
1 2 3 | result = 3 result = 7 result = NaN |
号
因为第一个
在其他答案中很难找到一个非常简单的心理作图反应:
done 执行tap 就像蓝鸟的承诺一样。then 按照es6承诺执行then 。
实际上,如果你不打算在一个承诺上附加更多的步骤,你应该使用