2012-06-18 8 views
5

So wurde ich in einem Interview gefragt, aber es brachte einen guten Anwendungsfall auf. Angenommen, Sie haben eine Reihe von Datenquellen. Sie möchten den ersten verfügbaren finden und ihn verarbeiten und den Rest ignorieren.Finde die erste verfügbare Datenquelle mit jQuery Deferred

So etwas wie:

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

ignorieren, dass ich glaube wirklich nicht, wenn ein Array akzeptiert (vielleicht ist es der Fall ist). Das würde natürlich warten lassen, bis alle fertig sind. Ich suche nach einem Code, der es warten lassen würde, bis einer von ihnen fertig ist, und sich dann keine Sorgen um die anderen machen.

Ich wurde informiert, dass es nur rekursiv arbeiten würde.

+0

Sollten sie alle zur gleichen Zeit starten, oder die zweite, wenn der erste gescheitert? – Bergi

+0

@Bergi Ich denke, beides wird funktionieren, ich denke beide sind in verschiedenen Anwendungsfällen optimal. – Parris

+0

Ja, aber ihr Konzept ist sehr unterschiedlich. Also welche brauchst du? – Bergi

Antwort

3

Dies verwendet keine Rekursion, sondern passt die Anforderung zum Abrufen von mehreren Datenquellen an und kümmert sich nur um die erste, die eine erfolgreiche Antwort zurückgibt.

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

Das ist eigentlich ziemlich toll, und Sie können sie alle gleichzeitig starten! Vielleicht gibt es auch eine Möglichkeit, die anderen Lookups zu stoppen. – Parris

+1

@Parris sicher, nur die aufgeschobenen irgendwo speichern und 'abort' auf sie im 'anyComplete' Handler aufrufen. Ich habe es bearbeitet. – Esailija

1

ich ein Plugin gemacht habe, die mit umgekehrter Semantik eines andere Version von $.when() zur Verfügung stellt. Es ist von der tatsächlichen jQuery-Implementierung von $.when() geändert, so ist es genau das gleiche wie das Original, außer dass es entweder auf die erste resolve d Versprechen wartet, oder alle versprochen, reject ed.

einfach diesen Code in der rechten fallen, nachdem Sie jQuery laden:

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