2014-02-02 7 views
0

Я искал много очень похожих вопросов. Я нашел тот, у которого было почти то, что я искал, за исключением того, что у него не было обработки ошибок, и при попытке реализовать обработку ошибок я сталкиваюсь с некоторыми проблемами.

Моя цель - создать функцию, которая получает массив имен, создает запросы $ .ajax в цикле, нажимая объекты с обещаниями на возврат в массив, который затем я предоставляю в $ .when.apply ($, arrayOfPromises). . затем (// и т.д., чтобы разрешить мастеру отложенное где все обещания в arrayOfPromises были решены Конечным результатом является то, чтобы создать массив данных, возвращаемых из Аякса вызовов

меня это до сих пор:. http://jsfiddle.net/BGx2h/1/

Это почти то, что мне нужно. Если массив содержит указатели на все допустимые ресурсы, все работает так, как планировалось. Однако, если есть вызов ресурса, он не существует (s uch как /test/doesnt.exist.txt в моей скрипке), вызов ajax для «doesnt.exist» заканчивается перед любым другим вызовом, мастер отложен (connectiondfd) получает разрешение до того, как другие вызовы имеют шанс закончить (вам может понадобиться запустить скрипку несколько раз, чтобы получить этот результат). Вот то, что моя функция выглядит в настоящее время:

function multiAsync() { 
    var i,data=[],connections=[], 
     targets=['John.Smith','Jane.Doe','Bob.Someone','doesnt.exist']; 

    var connectiondfd = $.Deferred(); 

    for(i=0;i<targets.length;i++) { 
     connections.push($.ajax({ 
      url:'http://porticium.ca/test/'+targets[i]+'.txt', 
      type:'GET', 
      async:true, 
      timeout:5000 
     }).then(function(newData) { 
      data.push(newData); 
     },function() { 
      data.push("NO DATA"); 
     })); 
} 

    $.when.apply($,connections) 
     .then(
      function() { connectiondfd.resolve(); }, 
      function() { connectiondfd.resolve(); } 
     ); 


    $.when(connectiondfd).done(function() { 
     alert("FINAL: " + data); 
    }); 
} 

бы определенно оценить некоторую помощь на этом, это было сводит меня с ума!

Спасибо, Роб

+0

с обработкой ошибок, в момент одна из обещаний терпит неудачу, вы получите сбой обработчика и никогда не получите успеха. Так как ваше неудачное обещание заканчивается почти мгновенно, оно всегда будет показывать неудачу до конца. Если это не функциональность, которую вы хотите, вы можете рассмотреть возможность использования чего-то другого, кроме отложенных объектов, например объекта $ .Callbacks. –

+0

Спасибо за ваш быстрый ответ. Сейчас я просматриваю $ .Callbacks. Таким образом, по существу нет способа сказать $ .when.apply ($, listOfPromises) .whenALLPromisesHaveResolvedOrRejected (function() {}); таким образом, и я не просто что-то упустил? – robgood

+0

правильный. как только один проваливается, это происходит в ожидании. –

ответ

0

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

function completed(firstParam) { 

     var args = _.toArray(arguments), 
      i = 0, 
      length = args.length, 
      pValues = new Array(length), 
      count = length, 
      deferred = length <= 1 && firstParam && $.isFunction(firstParam.promise) ? firstParam : $.Deferred(), 
      promise = deferred.promise(), 
      state = 'resolved'; 

     function alwaysFunc(i) { 

      return function (value) { 

       args[ i ] = arguments.length > 1 ? _.toArray(arguments) : value; 
       state = (this.state && this.state() === 'rejected') ? 'rejected' : state; 
       if (!(--count)) deferred[ (state === 'rejected' ? 'reject' : 'resolve') + 'With' ](deferred, args); 

      }; 

     } 

     function progressFunc(i) { 

      return function (value) { 

       pValues[ i ] = arguments.length > 1 ? _.toArray(arguments) : value; 
       deferred.notifyWith(promise, pValues); 

      }; 

     } 

     if (length > 1) { 

      for (; i < length; i++) { 

       if (args[ i ] && args[ i ].promise && $.isFunction(args[ i ].promise)) 
        args[ i ].promise().always(alwaysFunc(i)).progress(progressFunc(i)); 

       else --count; 

      } 

      if (!count) deferred.resolveWith(deferred, args); 

     } else if (deferred !== firstParam) deferred.resolveWith(deferred, length ? [ firstParam ] : []); 

     return promise; 

    } 

Во всяком случае, вы создаете и присоединять обработчик для отдельных запросов/promisses как обычно, затем передают их через эту функцию через apply. Состояние каждого запроса обрабатывается отдельно, и функция отслеживает, сколько еще не разрешено. Как только все будут разрешены, он запускает собственное разрешение, основанное на коллекции. Даже если одно или все обещания компонента терпят неудачу, все они все еще выполняются, и ведущий Отсроченный ждет, пока все они не будут решены. Он не обрабатывает добавление дополнительных обещаний/отсрочек после первоначального вызова - создайте все, что вам нужно, а затем передайте их этой функции.

Я не могу взять кредит на сценарий: он был «передан» мне через коллега, которого я предполагаю получить из какого-то другого места, но был худшим человеком в мире для хранения комментариев/атрибутов в коде , Если кто-то узнает код и может указать мне в сторону автора ...

+0

Это работает как магия точно так, как мне это нужно. Я не могу сказать, что я все это понимаю, но я определенно знаю, что я буду изучать в течение следующего небольшого времени. Огромное спасибо. – robgood

2

Так что я играл с этим больше и изучал функцию, которая была предоставлена ​​в ответе, который я принял (спасибо снова!), И мне удалось узнайте другое решение, используя отложенное, которое соответствует моим целям.

Я создал функцию, называемую whenAll, которая принимает массив обещаний, создает мастер отложенных и добавляет выполненные и отказывает обратные вызовы для каждого обещания, которые выталкивают возвращенные данные или сообщение об ошибке в массив, а затем проверяет длина массива данных по отношению к длине предоставленного массива обещаний, если они совпадают.

Здесь:

function whenAll(promises) { 
    var i,data=[],dfd=$.Deferred(); 
    for(i=0;i<promises.length;i++) { 
     promises[i].done(function(newData) { 
      data.push(newData); 
      if(data.length==promises.length) { 
       dfd.resolve(data); 
      } 
     }).fail(function() { 
      data.push("NO DATA"); 
      if(data.length==promises.length) { 
       dfd.resolve(data); 
      }    
     }); 
    } 
    return dfd.promise(); 
}