2017-01-31 4 views
0

Использование $ .when на jquery для deffered ajax были некоторые недостатки. Это здорово, когда призывы ajax были успешно обработаны. Но если вы терпите неудачу, вы не можете получить другие данные по другому запросу.

Ex.

 

    var ajax1Success = function() { 
     return $.ajax(...); 
    }; 

    var ajax2Success = function() { 
     return $.ajax(...); 
    }; 

    var ajax3BoundtoFail = function() { 
     return $.ajax(...); 
    }; 


    $.when(ajax1Succes(), ajax2Success(), ajax3BoundtoFail()).done(function(a1, a2, a3) { 
     // all good 

    }).fail(function() { 
     // not good... ajax3 is bound to fail 
    }); 

Любое хорошее решение, как получить другие данные из запроса ajax, который преуспел?

ответ

1

$.when() имеет «неудачный быстрый» дизайн. Это означает, что первое обещание, которое терпит неудачу, вызывает отказ $.when(), и вы получаете информацию об отказе. С JQuery документ:

The method will resolve its master Deferred as soon as all the Deferreds resolve, or reject the master Deferred as soon as one of the Deferreds is rejected

Вы можете, однако, использовать другой тип функции, чтобы контролировать вашу группу обещаний. Этот тип функций часто называют «улаживать», когда вы ждете, пока все обещания не будут урегулированы, и вы получите результаты от всех из них независимо от того, решили ли они или отклонили.

Вот такая реализация для JQuery promies, что я использовал в прошлом, которые вы можете использовать, как это:

$.settle([ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) { 
    // results is an array of PromiseInspection Objects 
    // for each of them, you can see if the corresponding promise 
    // succeeded with a value or failed with an error 
    results.forEach(function(pi, index) { 
     if (pi.isFulfilled()) { 
      console.log("Promise #" + (index + 1) + " succeeded with result " + pi.value()); 
     } else { 
      console.log("Promise #" + (index + 1) + " failed with reason " + pi.reason()); 
     } 
    }); 
}); 

Или, немного проще версии использовать, если вам не нужно точное сообщение об ошибке:

$.settleVal(null, [ajax1Succes(), ajax2Success(), ajax3BoundtoFail()]).then(function(results) { 
    // results contains the results from all the successful promises 
    // any promises that has an error will show null as the result 
}); 

Обратите внимание, они используют интерфейс больше похож на стандартный Promise.all(), где они принимают массив обещаний и разрешения на массив результатов, так как это, как правило, как правило, легче использовать в реальном мире.

И вот реализация:

(function() {  

    function isPromise(p) { 
     return p && (typeof p === "object" || typeof p === "function") && typeof p.then === "function"; 
    } 

    function wrapInPromise(p) { 
     if (!isPromise(p)) { 
      p = $.Deferred().resolve(p); 
     } 
     return p; 
    } 

    function PromiseInspection(fulfilled, val) { 
     return { 
      isFulfilled: function() { 
       return fulfilled; 
      }, isRejected: function() { 
       return !fulfilled; 
      }, isPending: function() { 
       // PromiseInspection objects created here are never pending 
       return false; 
      }, value: function() { 
       if (!fulfilled) { 
        throw new Error("Can't call .value() on a promise that is not fulfilled"); 
       } 
       return val; 
      }, reason: function() { 
       if (fulfilled) { 
        throw new Error("Can't call .reason() on a promise that is fulfilled"); 
       } 
       return val; 
      } 
     }; 
    } 

    // pass either multiple promises as separate arguments or an array of promises 
    $.settle = function(p1) { 
     var args; 
     if (Array.isArray(p1)) { 
       args = p1; 
     } else { 
      args = Array.prototype.slice.call(arguments); 
     } 

     return $.when.apply($, args.map(function(p) { 
      // make sure p is a promise (it could be just a value) 
      p = wrapInPromise(p); 
      // Now we know for sure that p is a promise 
      // Make sure that the returned promise here is always resolved with a PromiseInspection object, never rejected 
      return p.then(function(val) { 
       return new PromiseInspection(true, val); 
      }, function(reason) { 
       // convert rejected promise into resolved promise by returning a resolved promised 
       // One could just return the promiseInspection object directly if jQuery was 
       // Promise spec compliant, but jQuery 1.x and 2.x are not so we have to take this extra step 
       return wrapInPromise(new PromiseInspection(false, reason)); 
      }); 
     })).then(function() { 
       // return an array of results which is just more convenient to work with 
       // than the separate arguments that $.when() would normally return 
      return Array.prototype.slice.call(arguments); 
     }); 
    } 

    // simpler version that just converts any failed promises 
    // to a resolved value of what is passed in, so the caller can just skip 
    // any of those values in the returned values array 
    // Typically, the caller would pass in null or 0 or an empty object 
    $.settleVal = function(errorVal, p1) { 
     var args; 
     if (Array.isArray(p1)) { 
       args = p1; 
     } else { 
      args = Array.prototype.slice.call(arguments, 1); 
     } 
     return $.when.apply($, args.map(function(p) { 
      p = wrapInPromise(p); 
      return p.then(null, function(err) { 
       return wrapInPromise(errorVal); 
      }); 
     })); 
    } 
})(); 
Смежные вопросы