Async: Maneira de determinar itens não processados ​​de async.map () após o erro ser emitido

Criado em 10 jul. 2017  ·  5Comentários  ·  Fonte: caolan/async

Oi,

Enquanto estiver usando map (...), há uma maneira de, ao lidar com um erro emitido pela função iteratee, determinar quantos itens ainda não foram processados ​​da coleção fornecida?

Estou usando map para realizar várias solicitações HTTP de saída (usando o nó request library) para uma matriz de diferentes urlsparams etc. do servidor de destino que posso controlar, mas quero reprocessar o item atual em que está sendo trabalhado e, a seguir, qualquer um que map ainda não tenha coletado.

Eu me perguntei sobre talvez definir um sinalizador em cada item da minha coleção que foi trabalhado com êxito (sem erros) e, em seguida, quando for emitido o erro no qual estou interessado, trate-o de acordo. Em seguida, talvez crie uma nova matriz dos itens com o sinalizador definido como falso para aqueles ainda não processados ​​e execute mais map sobre eles, certificando-se de invocar o retorno de chamada final original do mapa original.

Não tenho certeza se isso faz algum sentido, mas há alguma maneira de alcançar o que descrevi acima?

question

Comentários muito úteis

Olá @ parky128 , obrigado pela pergunta!

Envolver iteratee com reflect funcionaria? reflect sempre passa um objeto de resultado para callback , então, mesmo se um dos iteratee funcionar erros, map terminaria. Em seguida, você pode apenas iterar sobre o objeto results de map , verificar quais têm uma propriedade error e, em seguida, tratá-la de acordo. Você não teria que reprocessar nenhum item que map não tenha recolhido.

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

Caso contrário, para responder à sua pergunta, map sempre retorna um array . Você poderia iterar sobre esse array e verificar quais valores são undefined . Esses corresponderão aos itens que erraram, passaram undefined para seus callback , estavam em andamento quando error ocorreu ou não começou. A abordagem reflect é provavelmente a opção mais segura, já que undefined pode ser um resultado válido de uma chamada de iteratee .

Todos 5 comentários

Olá @ parky128 , obrigado pela pergunta!

Envolver iteratee com reflect funcionaria? reflect sempre passa um objeto de resultado para callback , então, mesmo se um dos iteratee funcionar erros, map terminaria. Em seguida, você pode apenas iterar sobre o objeto results de map , verificar quais têm uma propriedade error e, em seguida, tratá-la de acordo. Você não teria que reprocessar nenhum item que map não tenha recolhido.

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

Caso contrário, para responder à sua pergunta, map sempre retorna um array . Você poderia iterar sobre esse array e verificar quais valores são undefined . Esses corresponderão aos itens que erraram, passaram undefined para seus callback , estavam em andamento quando error ocorreu ou não começou. A abordagem reflect é provavelmente a opção mais segura, já que undefined pode ser um resultado válido de uma chamada de iteratee .

Obrigado por oferecer uma solução potencial. Na verdade, eu gostaria que o retorno de chamada final async.map fosse invocado assim que um dos erros de função iteratee com o caso de erro específico que estou tentando detectar.

Olhando para a documentação, vejo que posso fazer isso passando um erro para a função de retorno de chamada iteratê, mas estou me perguntando se no retorno de chamada final que async.map invocará, se eu poderia apenas usar esse objeto de resultados para comparar com o original coleta e veja o que resta para processar.

Só não quero que async.map tente processar nenhuma outra solicitação assim que uma delas retornar o caso de erro no qual estou interessado.

Só não quero que async.map tente processar nenhuma outra solicitação assim que uma delas retornar o caso de erro no qual estou interessado.

Supondo que iteratee seja assíncrono, async.map terá iniciado o processamento de todos os itens quando o retorno de chamada final for invocado. Você poderia potencialmente comparar o objeto de resultados à coleção para ver quais itens ainda não concluíram o processamento, mas isso também tem suas pegadinhas. Por exemplo, você teria que fazer isso de forma síncrona, no mesmo tick o retorno de chamada final é invocado, pois o objeto de resultados será atualizado como iteratee s resolve.

Você pode tentar mapSeries . mapSeries executará apenas uma solicitação de cada vez. ou seja, ele só chama o próximo item quando o atual termina o processamento (em vez de iniciar todos de uma vez). Isso significa que quando ocorre um erro e o retorno de chamada final é invocado, nenhum outro iteratee s será executado. Você pode então comparar os resultados com a coleção para ver quais itens ainda não foram processados. Isso ainda é um pouco como uma solução alternativa, mas é melhor do que usar async.map . A principal desvantagem dessa abordagem é que as solicitações não são mais tratadas em paralelo.

Por exemplo, se sua coleção é uma 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, sim, minha função iteratee é assíncrona, pois ela usa a biblioteca de solicitações para fazer uma solicitação http de saída e eu retorno dela com o resultado. Portanto, se eu disser que há 10 itens para iterar, 4 foram bem-sucedidos e o 5º falhou, o que eu invocaria o retorno de chamada para a função iteratee com um parâmetro de erro, isso significa que o objeto de resultados no retorno de chamada final para async.map conterá apenas os 4 resultados de sucesso?

Se isso acontecer, por enquanto, viverei com o fato de que ele ainda fará todas as chamadas de saída. Posso dividir minha matriz em matrizes menores e executar async.maps menores em um mapSeries para minimizar o acerto inicial no servidor de destino que as solicitações estão atingindo.

@hargasinski - Acabei usando a abordagem async.reflect e isso está funcionando bem para mim, me dá visibilidade total de todos os itens que deram um erro: +1:

Obrigado!

Esta página foi útil?
0 / 5 - 0 avaliações