Остановить выполнение обещаний после разрешения первого обещания

Я использую обещания ES6, идея этой функции состоит в том, чтобы перебирать массив ссылок, и для каждой ссылки искать изображение и останавливаться, как только изображение найдено.

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

scrapImage(links) {
  let promises = links.map((l) => getImageUrlAsync(l));
  return Promise.race(promises);
}

person zianwar    schedule 14.03.2016    source источник
comment
Какова цель этого? Чего вы на самом деле пытаетесь достичь? Обещания ES6 нельзя отменить, но некоторые сторонние библиотеки обещаний (например, Bluebird) поддерживают отмену.   -  person JLRishe    schedule 14.03.2016
comment
Я хочу остановить выполнение обещаний после разрешения первого, если это невозможно с обещаниями es6, как я могу этого добиться?   -  person zianwar    schedule 14.03.2016
comment
Нет, цель не ясна. Почему вы хотите остановить выполнение промисов? Какой цели это служит?   -  person JLRishe    schedule 14.03.2016
comment
Допустим, getImageUrlAsync() выполняет большую работу для каждого элемента массива, не разумно ли прекращать выполнение других обещаний для повышения производительности, как только я получу свой результат?   -  person zianwar    schedule 14.03.2016
comment
Это будет зависеть от того, будет ли основная часть этой работы продолжаться после того, как первое обещание будет полностью разрешено, или большая часть работы будет выполнена к этому моменту. Я предлагаю запустить несколько тестов, чтобы убедиться, что это не преждевременная оптимизация. В настоящее время не существует стандартного подхода к отмене обещаний. Вот документ об отмене в bluebird, а bluebird — отличная библиотека, поэтому, если вы действительно нужно отменить, это был бы прекрасный выбор.   -  person JLRishe    schedule 14.03.2016
comment
К тому времени, когда вы знаете, что хотите отменить другие обещания, предполагая, что getImageUrlAsync является вызовом ajax, запрос уже отправлен, и сервер начал работать над ним. Вы можете отменить запрос, но это не помешает серверу продолжить работу над ним. Если на стороне сервера есть большие накладные расходы при обработке запроса, который вы хотите отменить, вам понадобится какой-то специальный механизм, чтобы предупредить сервер о прекращении обработки. В общем, кажется, не стоит заморачиваться, за исключением особых ситуаций.   -  person    schedule 14.03.2016


Ответы (2)


Обещания не «исполняются». Это возвращаемые значения, а не функции. Обещание не является управляющей поверхностью для какой бы то ни было функции, возвращающей его. Похоже, вы хотите отменить getImageUrlAsync(), поэтому я бы поискал API отмены в любом из этих API.

В отсутствие такого API отмены лучшее, что вы можете сделать, это Promise.race в массиве промисов, что вы и делаете. Как указывали другие, когда все работает параллельно, может быть уже слишком поздно вспоминать другие запущенные действия.

person jib    schedule 14.03.2016

Я бы сказал, что невозможно остановить выполнение, потому что все промисы запускаются одновременно при использовании Promise.race.

Попробуйте использовать цикл, например while.

Некоторый пример кода с использованием ES7, если вы используете babel.

async doSomething(links) {
  let l = links.length;
  while (l--) {
    let res = await getImageUrlAsync(links[l]);
    if (res) {
      break;
    }
  }
}
person Ivan Nosov    schedule 14.03.2016