2012-06-18 13 views
5

Così mi è stato chiesto in un'intervista, ma ha sollevato un buon caso d'uso. Supponiamo che tu abbia un sacco di fonti di dati. Vuoi trovare il primo disponibile, elaborarlo e ignorare il resto.Trova la prima fonte di dati disponibile con jQuery differita

Quindi qualcosa di simile:

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

Ignora che io davvero non credo che quando si accetta un array (forse lo fa). Questo naturalmente lo farebbe attendere fino a quando non saranno tutti completati. Sto cercando un codice che lo faccia aspettare fino a quando uno di loro è finito, e quindi non preoccuparsi degli altri.

Sono stato informato che avrebbe funzionato solo in modo ricorsivo.

+0

Dovrebbero iniziare tutto allo stesso tempo, o il secondo quando il primo fallito? – Bergi

+0

@Bergi Penso che funzioneranno entrambi, penso che entrambi siano ottimali in vari casi d'uso. – Parris

+0

Sì, ma il loro concetto è molto diverso. Quindi di quale hai bisogno? – Bergi

risposta

3

Questo non utilizza la ricorsione ma soddisfa il requisito di recuperare da più origini dati e si preoccupa solo del primo che restituisce una risposta corretta.

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

Questo è davvero fantastico, e ti permette di avviarli tutti in una volta! Forse c'è anche un modo per fermare anche gli altri lookup. – Parris

+1

@Parris sicuro, basta memorizzare i differiti da qualche parte e chiamare 'abort' su di essi nel gestore' anyComplete'. L'ho modificato in – Esailija

1

Ho fatto un plugin che fornisce un'altra versione di $.when() con la semantica invertiti. È stato modificato dall'attuale implementazione jQuery di $.when(), quindi è esattamente la stessa dell'originale eccetto il fatto che attende la prima o la resolve d promessa, o tutto promesso di essere reject ed.

Basta inserire questo codice in proprio dopo aver caricato 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); 
Problemi correlati