【问题标题】:Why jQuery's Promise.reject does not working?为什么 jQuery 的 Promise.reject 不起作用?
【发布时间】:2017-12-01 17:29:11
【问题描述】:

我正在使用 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!

【问题讨论】:

    标签: javascript jquery ruby-on-rails ajax promise


    【解决方案1】:

    在您的示例中,您使用的是来自ECMAScript 2015 specificationPromise,而不是jQuery 的Deferred 类promise 对象。

    所以不是这一行:

    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 
    

    解决方案 2

    如果要使用ECMAScript2015 Promise,可以将jQuery的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);
        });
    }
    

    请注意,您需要在链的末尾使用catch(...) 而不是fail(...),因为fail 是jQuery Deferred 的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多