Async: Manera de determinar los elementos no procesados ​​de async.map () después de que se emite un error

Creado en 10 jul. 2017  ·  5Comentarios  ·  Fuente: caolan/async

Hola,

Mientras se usa map (...), ¿hay alguna manera al manejar un error emitido por la función iteratee para determinar cuántos elementos aún no se han procesado de la colección proporcionada?

Estoy usando map para realizar múltiples solicitudes HTTP salientes (usando el nodo request biblioteca) para una matriz de diferentes urlsparams, etc. En parte al realizar cualquiera de estas solicitudes, puedo obtener un error particular desde el servidor de destino que puedo manejar, pero luego quiero volver a procesar el elemento actual en el que se está trabajando y luego los restantes que map aún no haya recogido.

Me pregunté si podría establecer una bandera en cada elemento de mi colección en el que se haya trabajado con éxito (sin error), y luego, cuando se emita el error que me interesa, manejarlo en consecuencia. Luego, tal vez cree una nueva matriz a partir de los elementos con la bandera establecida en falso para aquellos que aún no se han procesado y realice map adicionales sobre estos, asegurándose de invocar la devolución de llamada final original desde el mapa original.

No estoy seguro de si esto tiene algún sentido, pero ¿hay alguna forma de lograr lo que he descrito anteriormente?

question

Comentario más útil

Hola @ parky128 , ¡gracias por la pregunta!

¿Funcionaría envolver el iteratee con reflect ? reflect siempre pasa un objeto de resultado al callback , por lo que incluso si uno de los errores de las funciones iteratee , map terminaría. Luego, simplemente podría iterar sobre el objeto results de map , verificar cuáles tienen una propiedad error y luego manejarlo en consecuencia. No tendría que volver a procesar ningún artículo que map no haya recogido.

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

De lo contrario, para responder a su pregunta, map siempre devuelve un array . Puede iterar sobre esa matriz y verificar qué valores son undefined . Esos corresponderán a los artículos que tuvieron errores, pasaron undefined a sus callback , estaban en progreso cuando ocurrió el error o no habían comenzado. Sin embargo, el enfoque reflect es probablemente la opción más segura, ya que undefined puede ser un resultado válido de una llamada iteratee .

Todos 5 comentarios

Hola @ parky128 , ¡gracias por la pregunta!

¿Funcionaría envolver el iteratee con reflect ? reflect siempre pasa un objeto de resultado al callback , por lo que incluso si uno de los errores de las funciones iteratee , map terminaría. Luego, simplemente podría iterar sobre el objeto results de map , verificar cuáles tienen una propiedad error y luego manejarlo en consecuencia. No tendría que volver a procesar ningún artículo que map no haya recogido.

async.map(coll, async.reflect(function(val, callback) {
  // your request code
}, function(err, results) {
  // err will always be null now
  results.forEach(function(result, i) {
    if (result.error) {
      // your code for handling errors
      // if `coll` is an array, you could access the value that caused 
      // this error through `coll[i]` as `map` preserves the order for arrays 
    } else {
      // otherwise `result.value` will contain the result of that `iteratee` call
    }
  });
});

De lo contrario, para responder a su pregunta, map siempre devuelve un array . Puede iterar sobre esa matriz y verificar qué valores son undefined . Esos corresponderán a los artículos que tuvieron errores, pasaron undefined a sus callback , estaban en progreso cuando ocurrió el error o no habían comenzado. Sin embargo, el enfoque reflect es probablemente la opción más segura, ya que undefined puede ser un resultado válido de una llamada iteratee .

Gracias por tomarse el tiempo para ofrecer una posible solución. De hecho, me gustaría que la devolución de llamada final async.map se invocara tan pronto como uno de los errores de funciones iteratee con el caso de error particular que estoy buscando detectar.

Al mirar los documentos, veo que puedo lograr esto pasando un error a la función de devolución de llamada iteratee, pero me pregunto si en la devolución de llamada final que invocará async.map, si podría usar ese objeto de resultados para comparar con el original recopilación y ver qué queda por procesar.

Simplemente no quiero que async.map intente procesar otras solicitudes tan pronto como una de estas devuelva el caso de error que me interesa.

Simplemente no quiero que async.map intente procesar otras solicitudes tan pronto como una de estas devuelva el caso de error que me interesa.

Suponiendo que su iteratee es asíncrono, async.map habrá comenzado a procesar todos los elementos cuando se invoque la devolución de llamada final. Potencialmente, podría comparar el objeto de resultados con la colección para ver qué elementos aún no han terminado de procesarse, pero eso también tiene sus inconvenientes. Por ejemplo, tendría que hacerlo sincrónicamente, en la misma marca se invoca la devolución de llamada final, ya que el objeto de resultados se actualizará como iteratee s resolve.

Podrías probar mapSeries . mapSeries solo ejecutará una solicitud a la vez. es decir, solo llama al siguiente elemento cuando el actual termina de procesarse (en lugar de iniciarlos todos a la vez). Esto significa que cuando ocurre un error y se invoca la devolución de llamada final, no se ejecutarán más iteratee s. Luego, podría comparar los resultados con la colección para ver qué elementos aún no se han procesado. Esto todavía es una pequeña solución, pero es mejor que usar async.map . Sin embargo, el principal inconveniente de este enfoque es que las solicitudes ya no se manejan en paralelo.

Por ejemplo, si su colección es una matriz

async.mapSeries(coll, function(val, callback) {
  // your iteratee function
}, function(err, results) {
  if (err) {
    // unprocessItems will include the item that errored.
    var unprocessItems = coll.slice(results.length - 1);
    // handle the unprocessedItems
  }
});

Hmm Ok, sí, mi función iteratee es asincrónica, ya que usa la biblioteca de solicitudes para hacer una solicitud http saliente y devuelvo la llamada con el resultado. Entonces, si digo que tenía 10 elementos para iterar, 4 tuvieron éxito y el quinto falló, lo que luego invocaría la devolución de llamada a la función iteratee con un parámetro de error, si eso significa que el objeto de resultados en la devolución de llamada final a async.map solo contendrá los 4 resultados exitosos?

Si es así, por ahora viviré con el hecho de que seguirá haciendo todas las llamadas salientes. En el futuro, puedo ser un yo para dividir mi matriz en matrices más pequeñas y realizar mapas asíncronos más pequeños dentro de un mapSeries para minimizar el acceso inicial al servidor de destino que reciben las solicitudes.

@hargasinski - Terminé usando el enfoque async.reflect y esto me está funcionando bien, me brinda una visibilidad completa de todos los elementos que dieron un error: +1:

¡Gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones