2012-06-18 6 views
5

Me lo preguntaron en una entrevista, pero me planteó un buen caso de uso. Supongamos que tiene un montón de fuentes de datos. Desea encontrar el primero disponible y procesarlo e ignorar el resto.Buscar la primera fuente de datos disponible con jQuery Deferred

Así que algo como:

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

ignorar que yo realmente no creo que cuando se acepta una matriz (tal vez lo hace). Esto, por supuesto, lo haría esperar hasta que todos estén completados. Estoy buscando algún código que lo haga esperar hasta que uno, cualquiera de ellos termine, y luego no se preocupe por los demás.

Me informaron que solo funcionaría recursivamente.

+0

En caso de que todo el comienzo que, al mismo tiempo, o el segundo cuando el primero se ha podido? – Bergi

+0

@Bergi Creo que cualquiera funcionará, creo que ambos son óptimos en varios casos de uso. – Parris

+0

Sí, pero su concepto es muy diferente. Entonces, ¿cuál necesitas? – Bergi

Respuesta

3

Esto no utiliza la recursividad, pero se ajusta al requisito de obtener de múltiples fuentes de datos y solo se preocupa por la primera que devuelve una respuesta exitosa.

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

¡Esto es realmente asombroso y te permite iniciarlos todos a la vez! Quizás también haya una manera de detener las otras búsquedas. – Parris

+1

@Parris seguro, solo almacena los diferidos en algún lugar y llama a 'abortar' sobre ellos en el controlador 'anyComplete'. Lo he editado en. – Esailija

1

He hecho un plugin que ofrece otra versión de $.when() con la semántica invertidos. Se ha modificado a partir de la implementación real de jQuery de $.when(), por lo que es exactamente igual que el original, excepto que espera la primera promesa resolve d, o todas prometieron ser reject ed.

tan sólo reduce este código en la derecha después de cargar 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); 
Cuestiones relacionadas