2012-06-18 16 views
5

Zostałem poproszony o to w wywiadzie, ale przyniósł dobry przypadek użycia. Załóżmy, że masz kilka źródeł danych. Chcesz znaleźć pierwszy dostępny i przetworzyć go i zignorować resztę.Znajdź pierwsze dostępne źródło danych z jQuery Odroczone

Więc coś takiego:

var datasources = new Array("somedatabase1/pizza","somedatabase2/beer","somedatabase3/llama"); 
var dfds = new Array(); 
$.each(datasources,function(source){ 
    dfds.push($.getJSON(source)); 
}); 

$.when(dfds).done(function(){alert("they are all done");}); 

ignorowanych, że ja naprawdę nie sądzę, kiedy akceptuje tablicę (może to robi). To oczywiście sprawi, że będzie czekać, aż wszystkie zostaną ukończone. Szukam kodu, który sprawi, że poczeka, aż jeden, którykolwiek z nich zostanie zrobiony, a potem nie martwi się o innych.

Zostałem poinformowany, że działa on tylko rekurencyjnie.

+0

powinny one rozpocząć w tym samym czasie, albo drugi, gdy pierwszy nie powiodło? – Bergi

+0

@Bergi Myślę, że albo zadziała, myślę, że obie są optymalne w różnych przypadkach użycia. – Parris

+0

Tak, ale ich koncepcja jest zupełnie inna. Więc który z nich potrzebujesz? – Bergi

Odpowiedz

3

Nie korzysta z rekursji, ale spełnia wymagania pobierania z wielu źródeł danych i zwraca uwagę tylko na pierwszą, która zwróci pomyślną odpowiedź.

http://jsfiddle.net/mNJ6D/

function raceToIt(urls) { 
    var deferred = $.Deferred(), 
     promises; 

    function anyComplete(data) { 
     if (!deferred.isResolved()) { 
      deferred.resolveWith(this, [data]); 
      promises.forEach(function(promise) { 
       promise.abort(); 
      }); 
     } 
    } 
    promises = urls.map(function(url) { 
     return $.getJSON(url).then(anyComplete); 
    }); 
    return deferred.promise(); 
} 
raceToIt(["/echo/json/", "/echo/json/", "/echo/json/"]).then(function(data) { 
    console.log(data); 
});​ 
+0

To jest naprawdę niesamowite, i pozwala uruchomić je wszystkie naraz! Być może istnieje również sposób na powstrzymanie innych spojrzeń. – Parris

+1

@Parris oczywiście, po prostu przechowuj odłożone gdzieś i wywołaj 'abort' na nich w procedurze' anyComplete'. Edytowałem to. – Esailija

1

zrobiłem plugin który stanowi kolejną wersję $.when() z odwróconym semantyki. Został zmodyfikowany z rzeczywistej implementacji jQuery: $.when(), więc jest dokładnie taki sam jak oryginalny, z tym, że czeka na pierwszą obietnicę, albo wszystko, co obiecał, to być wydane w wersji .

Wystarczy wrzucić ten kod w prawo po załadowaniu jQuery:

(function($) { 
    $.reverseWhen = function(subordinate /* , ..., subordinateN */) { 
    var i = 0, 
     rejectValues = Array.prototype.slice.call(arguments), 
     length = rejectValues.length, 

     // the count of uncompleted subordinates 
     remaining = length !== 1 || (subordinate && jQuery.isFunction(subordinate.promise)) ? length : 0, 

     // the master Deferred. If rejectValues consist of only a single Deferred, just use that. 
     deferred = remaining === 1 ? subordinate : jQuery.Deferred(), 

     // Update function for both reject and progress values 
     updateFunc = function(i, contexts, values) { 
     return function(value) { 
      contexts[ i ] = this; 
      values[ i ] = arguments.length > 1 ? Array.prototype.slice.call(arguments) : value; 
      if(values === progressValues) { 
      deferred.notifyWith(contexts, values); 
      } else if (!(--remaining)) { 
      deferred.rejectWith(contexts, values); 
      } 
     }; 
     }, 

     progressValues, progressContexts, rejectContexts; 

    // add listeners to Deferred subordinates; treat others as rejected 
    if (length > 1) { 
     progressValues = new Array(length); 
     progressContexts = new Array(length); 
     rejectContexts = new Array(length); 
     for (; i < length; i++) { 
     if (rejectValues[ i ] && jQuery.isFunction(rejectValues[ i ].promise)) { 
      rejectValues[ i ].promise() 
      .done(deferred.resolve) 
      .fail(updateFunc(i, rejectContexts, rejectValues)) 
      .progress(updateFunc(i, progressContexts, progressValues)); 
     } else { 
      --remaining; 
     } 
     } 
    } 

    // if we're not waiting on anything, reject the master 
    if (!remaining) { 
     deferred.rejectWith(rejectContexts, rejectValues); 
    } 

    return deferred.promise(); 
    }; 
})(jQuery); 
Powiązane problemy