Async: Способ определения необработанных элементов из async.map () после появления ошибки

Созданный на 10 июл. 2017  ·  5Комментарии  ·  Источник: caolan/async

Привет,

При использовании map (...) есть ли способ при обработке ошибки, вызванной функцией итератора, определить, сколько элементов еще не было обработано из предоставленной коллекции?

Я использую map для выполнения нескольких исходящих HTTP-запросов (с использованием библиотеки node request ) для массива различных URL-адресов и т. Д. В процессе выполнения любого из этих запросов я могу получить определенную ошибку с целевого сервера, с которым я могу справиться, но затем я хочу повторно обработать текущий элемент, над которым работает, а затем любые оставшиеся, которые map еще не подобраны.

Мне было интересно, может быть, установить флаг для каждого элемента в моей коллекции, который был успешно обработан (без ошибок), а затем, когда возникнет ошибка, которая меня интересует, обработайте ее соответствующим образом. Затем, возможно, создайте новый массив из элементов с флагом, установленным в false для тех, которые еще не обработаны, и выполните еще map над ними, убедившись, что я вызываю исходный окончательный обратный вызов из исходной карты.

Не уверен, имеет ли это какой-то смысл, но есть ли способ достичь того, что я описал выше?

question

Самый полезный комментарий

Привет @ parky128 , спасибо за вопрос!

Будет ли работать упаковка iteratee с reflect ? reflect всегда передает объект результата в callback , поэтому, даже если одна из ошибок iteratee functions, map завершится. Затем вы можете просто перебрать объект results из map , проверить, какие из них имеют свойство error , а затем обработать его соответствующим образом. Вам не придется повторно обрабатывать предметы, которые map могли не подобрать.

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

В противном случае, чтобы ответить на ваш вопрос, map всегда возвращает array . Вы можете перебрать этот массив и проверить, какие значения равны undefined . Они будут соответствовать элементам, которые были ошибочными, передали undefined их callback , находились в процессе выполнения, когда произошла ошибка error или не были запущены. Подход reflect вероятно, является более безопасным вариантом, поскольку undefined может быть допустимым результатом вызова iteratee .

Все 5 Комментарий

Привет @ parky128 , спасибо за вопрос!

Будет ли работать упаковка iteratee с reflect ? reflect всегда передает объект результата в callback , поэтому, даже если одна из ошибок iteratee functions, map завершится. Затем вы можете просто перебрать объект results из map , проверить, какие из них имеют свойство error , а затем обработать его соответствующим образом. Вам не придется повторно обрабатывать предметы, которые map могли не подобрать.

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

В противном случае, чтобы ответить на ваш вопрос, map всегда возвращает array . Вы можете перебрать этот массив и проверить, какие значения равны undefined . Они будут соответствовать элементам, которые были ошибочными, передали undefined их callback , находились в процессе выполнения, когда произошла ошибка error или не были запущены. Подход reflect вероятно, является более безопасным вариантом, поскольку undefined может быть допустимым результатом вызова iteratee .

Спасибо, что нашли время предложить потенциальное решение. На самом деле я бы хотел, чтобы конечный обратный вызов async.map запускался, как только одна из ошибок iteratee functions с конкретным случаем ошибки, который я ищу.

Глядя на документы, я вижу, что могу добиться этого, передав ошибку в функцию обратного вызова итерации, но мне интересно, будет ли в последнем обратном вызове, который вызовет async.map, просто использовать этот объект результатов для сравнения с исходным сбор и посмотрите, что осталось обработать.

Я просто не хочу, чтобы async.map пытался обрабатывать любые другие запросы, как только один из них вернет интересующий меня случай ошибки.

Я просто не хочу, чтобы async.map пытался обрабатывать любые другие запросы, как только один из них вернет интересующий меня случай ошибки.

Предполагая, что ваш iteratee асинхронный, async.map начнет обработку всех элементов при вызове последнего обратного вызова. Вы можете сравнить объект результатов с коллекцией, чтобы увидеть, какие элементы еще не завершили обработку, но у этого также есть свои подводные камни. Например, вам нужно будет сделать это синхронно, в тот же самый тик будет вызван последний обратный вызов, поскольку объект результатов будет обновлен как разрешение iteratee s.

Вы можете попробовать mapSeries . mapSeries будет запускать только один запрос за раз. т.е. он вызывает следующий элемент только тогда, когда текущий завершает обработку (в отличие от запуска всех сразу). Это означает, что когда возникает ошибка и вызывается последний обратный вызов, больше iteratee s запускаться не будет. Затем вы можете сравнить результаты с коллекцией, чтобы увидеть, какие элементы еще не были обработаны. Это все еще небольшой обходной путь, но он лучше, чем использование async.map . Однако основным недостатком этого подхода является то, что запросы больше не обрабатываются параллельно.

Например, если ваша коллекция представляет собой массив

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

Хм Хорошо, да, моя функция iteratee является асинхронной, поскольку она использует библиотеку запросов для выполнения исходящего HTTP-запроса, и я выполняю обратный вызов от нее с результатом. Итак, если я скажу, что у меня было 10 элементов для итерации, 4 были выполнены успешно, а 5-й не удалось, что я бы затем вызвал обратный вызов функции итерации с параметром ошибки, если это означает, что объект результатов в последнем обратном вызове async.map будет содержать только 4 успешных результата?

Если это так, то пока я буду жить с тем фактом, что он по-прежнему будет выполнять все исходящие звонки. Я могу разделить свой массив на более мелкие массивы и выполнить более мелкие async.maps в mapSeries, чтобы минимизировать начальное попадание на целевой сервер, с которым сталкиваются запросы.

@hargasinski - в async.reflect и он отлично работает для меня, дает мне полную видимость всех элементов, которые выдавали ошибку: +1:

Спасибо!

Была ли эта страница полезной?
0 / 5 - 0 рейтинги