我正在使用REST API,类似于这个存根:Snippet 1(Ruby on Rails示例)。
我在经典回调中有现有的jQuery代码:Snippet 2
使用日志执行:
case 1:
[INFO] /api/my/action1: got rejecting signal, do not continue
case 2:
[INFO] /api/my/action1: no rejecting signal, continue
[INFO] /api/my/action2: no rejecting signal, continue
[INFO] /api/my/action3: hurrah!! we got message: Third action executed!
case 3:
[INFO] /api/my/action1: no rejecting signal, continue
[ERROR] Got error with message: Unexpected error
我想将此代码重构为承诺:
function ajxGet(url){
return $.ajax({
url,
dataType: 'JSON'
})
}
export function makeThreeAsyncQueries(){
ajxGet('/api/my/action1')
.then(response1 => {
if(response1.do_reject_other_actions){
console.log('[INFO] /api/my/action1: got rejecting signal, do not continue');
return Promise.reject({mute: true});
}else{
console.log('[INFO] /api/my/action1: no rejecting signal, continue');
return ajxGet('/api/my/action2');
}
})
.then(response2 => {
if(response2.do_reject_other_actions){
console.log('[INFO] /api/my/action2: got rejecting signal, do not continue');
return Promise.reject({mute: true});
}else{
console.log('[INFO] /api/my/action2: no rejecting signal, continue');
return ajxGet('/api/my/action3');
}
})
.then(response3 => {
console.log('[INFO] /api/my/action3: hurrah!! we got message: ', response3.message);
})
.fail((err) => {
if(err && err.mute){
console.log('[INFO] normal chain break.');
return
}
console.info('[ERROR] Got error with message:', err.responseJSON.message);
});
}
问题是Promise.reject({mute: true});
不起作用,我有这些日志:
[INFO] /api/my/action1: got rejecting signal, do not continue <<-- SHOULD STOP HERE
[INFO] /api/my/action2: no rejecting signal, continue
Uncaught (in promise) Object {mute: true}
<...callstack here...>
[INFO] /api/my/action3: hurrah!! we got message: Third action executed!
答案 0 :(得分:1)
在您的示例中,您使用Promise中的ECMAScript 2015 specification而不是jQuery的Deferred类似承诺的对象。
所以不是这一行:
return Promise.reject({mute: true});
使用此:
return $.Deferred().reject({ mute: true })
完整的代码示例:
function ajxGet(url){
return $.ajax({
url,
dataType: 'JSON'
})
}
export function makeThreeAsyncQueries(){
ajxGet('/api/my/action1')
.then(response1 => {
if(response1.do_reject_other_actions){
console.log('[INFO] /api/my/action1: got rejecting signal, do not continue');
return $.Deferred().reject({ mute: true })
}else{
console.log('[INFO] /api/my/action1: no rejecting signal, continue');
return ajxGet('/api/my/action2');
}
})
.then(response2 => {
if(response2.do_reject_other_actions){
console.log('[INFO] /api/my/action2: got rejecting signal, do not continue');
return $.Deferred().reject({ mute: true })
}else{
console.log('[INFO] /api/my/action2: no rejecting signal, continue');
return ajxGet('/api/my/action3');
}
})
.then(response3 => {
console.log('[INFO] /api/my/action3: hurrah!! we got message: ', response3.message);
})
// as argument here we will get jquery's xhr object on AJAX-error, or will get payload sent by $.deferred().reject
.fail((xhr) => {
if(xhr && xhr.mute){
console.log('[INFO] normal chain break.');
return
}
console.info('[ERROR] Got error with message:', xhr.responseJSON.message);
});
}
所以当后端返回do_reject_other_actions === true
时,链会断开,你会得到这个正确的日志:
[INFO] /api/my/action1: got rejecting signal, do not continue
[INFO] normal chain break.
or
[INFO] /api/my/action1: no rejecting signal, continue
[INFO] /api/my/action2: got rejecting signal, do not continue
[INFO] normal chain break.
or
[INFO] /api/my/action1: no rejecting signal, continue
[INFO] /api/my/action2: no rejecting signal, continue
[INFO] /api/my/action3: hurrah!! we got message: Third action executed!
or
[INFO] /api/my/action1: no rejecting signal, continue
[ERROR] Got error with message: Unexpected error
如果您想使用ECMAScript2015 Promise,可以将jQuery&#39; ajax
包装到Promise中:
function ajxGet(url){
return new Promise((resolve, reject) => {
$.ajax({
url,
dataType: 'JSON',
success: response => resolve(response),
error: (xhr) => { reject(xhr) },
})
});
}
export function makeThreeAsyncQueries(){
ajxGet('/api/my/action1')
.then(response1 => {
if(response1.do_reject_other_actions){
console.log('[INFO] /api/my/action1: got rejecting signal, do not continue');
return Promise.reject({mute: true});
}else{
console.log('[INFO] /api/my/action1: no rejecting signal, continue');
return ajxGet('/api/my/action2');
}
})
.then(response2 => {
if(response2.do_reject_other_actions){
console.log('[INFO] /api/my/action2: got rejecting signal, do not continue');
return Promise.reject({mute: true});
}else{
console.log('[INFO] /api/my/action2: no rejecting signal, continue');
return ajxGet('/api/my/action3');
}
})
.then(response3 => {
console.log('[INFO] /api/my/action3: hurrah!! we got message: ', response3.message);
})
.catch((xhr) => {
if(xhr && xhr.mute){
console.log('[INFO] normal chain break.');
return
}
console.info('[ERROR] Got error with message:', xhr.responseJSON.message);
});
}
请注意,代替fail(...)
,您需要在链的末尾使用catch(...)
,因为fail
是jQuery Deferred的方法。