2016-12-01 7 views
1

Say У меня есть функции отложенной:

Попытка 1:

$.when(validatePerson(123), validatePerson(456)) 
.done(function(data) { }) 
.fail(function(data1, data2) { }); 

Попытка 2:

$.when(validatePerson(123), validatePerson(456)) 
.done(function(data) { }) 
.fail(function(data1) { }, 
     function(data2) { }); 

Я хочу, чтобы 2 AJAX вызывал асинхронно, но в случае отказа я хочу узнать, какой из 1-го, 2-го или обоих вызовов fai поэтому я могу отобразить соответствующую ошибку для пользователя.

например.

  • Подтверждено Person 1 (ID 123) не
  • Validated Person 2 (ID 456) не

Но я не могу заставить его работать. В попытке 1 параметр data1 содержит только один из результатов, и data2 не определен.

В попытке 2 Я получаю функцию обратного вызова функции дважды с тем же аргументом.

+0

это не возможно с помощью JQuery? Будет ли это работать в IE11, поскольку я вижу Обещания как вещь ES6? – user183872

ответ

0

$.when() завершается, когда первое обещание, которое вы передаете, отклоняется. Вы не можете получить от него все отклоненные обещания. Вы можете использовать его с другим кодом для отслеживания всех сбоев.

Вот $.settle(), что ждет всех обещаний вы передать его либо разрешить или отклонить и возвращает массив объектов PromiseInspection, из которого вы можете сказать, которые разрешены и которые отвергли и то, что их разрешенные значения или отвергаются причины:

(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); 
      }); 
     })); 
    } 
})(); 

Использование:

$.settle(arrayOfPromises).then(function(results) { 
    // results is an array of PromiseInspection objects and you can 
    // tell which are resolved and which are rejected 
    results.forEach(function(item, index) { 
     if (item.isFulfilled()) { 
      console.log("promise #" + index + " is fulfilled with value: ", item.value();); 
     } else { 
      console.log("promise #" + index + " is rejected with reason: ", item.reason();); 
     } 
    }); 
}); 
+0

Спасибо, но это много кода для всего 2 обратных звонков ajax! Также мне интересно, какова цель массива обратных вызовов в функции fail()? – user183872

+0

@ user183872 - '$ .when()' отклоняется, как только первое обещание терпит неудачу, поэтому у вас нет НИКАКОЙ возможности узнать, что случилось с другими обещаниями. Это просто не работает. Вы можете передать несколько обратных вызовов в '.fail()', и это всего лишь несколько обратных вызовов для одного и того же события. Он будет называть каждого из них один за другим, все с той же информацией. – jfriend00

+0

@ user183872 - Вы должны думать об этом как о инструменте, который является расширением jQuery. Вы добавляете его в свой проект, чтобы вы могли использовать '$ .settle()' в любое время, когда хотите увидеть все результаты всех обещаний независимо от разрешения или отклонения. Затем вы просто используете его вместо '$ .when()', когда это то, что вы хотите. Это не то, что вы набираете каждый раз, когда хотите его использовать. – jfriend00