我一直在阅读jQuery的延迟和承诺,我看不出使用.then()和.done()成功回调之间的区别。我知道Eric Hynds提到.done()和.success()映射到相同的功能,但我猜.then()也是如此,因为所有的回调都是在成功操作完成时调用的。
有人能告诉我正确的用法吗?
我一直在阅读jQuery的延迟和承诺,我看不出使用.then()和.done()成功回调之间的区别。我知道Eric Hynds提到.done()和.success()映射到相同的功能,但我猜.then()也是如此,因为所有的回调都是在成功操作完成时调用的。
有人能告诉我正确的用法吗?
当前回答
除了以上的答案:
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后面
其他回答
deferred.done ()
添加仅在Deferred被解析时调用的处理程序。您可以添加多个回调被调用。
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);
}
在回答中有一个非常简单的心理映射,在其他答案中很难找到:
done实现了蓝鸟承诺中的tap 然后实现然后在ES6承诺
只使用.then()
.done()没有优点,以下是缺点:
不能正确地连接 A.done ().done()与A.done()相同;A.done(),可以用a.then()来估计;交配制度() A.then ().then()与.done()不可能 块resolve()调用(所有.done()处理程序将同步执行) Resolve()可能会从已注册的.done()处理程序获取异常(!) .done()中的异常会将被延迟的对象减半: 进一步的.done()处理程序将被无声地跳过 .那么()就没有这些问题了
我暂时认为.then(oneArgOnly)总是需要.catch(),因此没有异常被无声地忽略,但这不再是真的:unhandledrejection事件在控制台上记录未处理的.then()异常(默认)。很合理的!完全没有理由使用.done()。
证明
下面的代码片段显示:
所有.done()处理程序将在resolve()点同步调用。 记录为1,3,5,7 在脚本掉到底部之前记录 .done()中的异常会影响resolve()调用者 通过catch around resolve()记录 异常打破了进一步.done()解析的承诺 8和10没有被记录! .那么()就没有这些问题了 在线程空闲后,记录为2,4,6,9,11 (片段环境似乎没有unhandledrejject)
顺便说一句,.done()的异常不能被正确捕获:由于.done()的同步模式,错误要么在.resolve()抛出(可能是库代码!),要么在.done()调用抛出,如果延迟已经解决,则该调用附加了罪魁祸首。
console.log('Start of script.'); let deferred = $.Deferred(); // deferred.resolve('Redemption.'); deferred.fail(() => console.log('fail()')); deferred.catch(()=> console.log('catch()')); deferred.done(() => console.log('1-done()')); deferred.then(() => console.log('2-then()')); deferred.done(() => console.log('3-done()')); deferred.then(() =>{console.log('4-then()-throw'); throw 'thrown from 4-then()';}); deferred.done(() => console.log('5-done()')); deferred.then(() => console.log('6-then()')); deferred.done(() =>{console.log('7-done()-throw'); throw 'thrown from 7-done()';}); deferred.done(() => console.log('8-done()')); deferred.then(() => console.log('9-then()')); console.log('Resolving.'); try { deferred.resolve('Solution.'); } catch(e) { console.log(`Caught exception from handler in resolve():`, e); } deferred.done(() => console.log('10-done()')); deferred.then(() => console.log('11-then()')); console.log('End of script.'); <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh" crossorigin="anonymous" ></script>
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
所有结果花费3。然后()函数总是将相同的延迟对象传递给下一个函数。
但是从jQuery 1.8开始,结果应该是:
result = 3
result = 7
result = NaN
因为第一个then()函数返回一个新的promise,值7(这是唯一要传递的参数)被传递给下一个done(),所以第二个done()将result = 7。第二个then()将7作为a的值,并将undefined作为b的值,因此第二个then()返回一个带有参数NaN的新承诺,最后一个done()打印NaN作为其结果。
.done()终止承诺链,确保没有其他步骤可以附加。这意味着jQuery承诺实现可以抛出任何未处理的异常,因为没有人可以使用.fail()处理它。
实际上,如果您不打算为承诺附加更多步骤,则应该使用.done()。要了解更多细节,请参阅为什么需要兑现承诺