Запускайте параллельные обещания и отбрасывайте отдых, когда два из них разрешены - PullRequest
0 голосов
/ 16 октября 2018

Я хочу собирать данные с 10 разных серверов одновременно, и когда я получил ответ 2 из них, я хочу игнорировать / пропускать другие.Я решил это с promise.all () Когда я получил 2 ответа, я вызываю отклонение вместо разрешения и выполняю свою работу в catch ().Но это кажется мне немного сложным, есть ли лучший способ сделать это?

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Вы должны взглянуть на BlueBird Promise.some

http://bluebirdjs.com/docs/api/promise.some.html

С учетом Iterable (массивы Iterable) или с обещанием Iterable, которое производитОбещания (или сочетание обещаний и значений), переберите все значения в Итерируемом в массив и верните обещание, которое выполнится, как только подсчеты выполнятся в массиве.Значение выполнения представляет собой массив со значениями счетчиков в порядке их выполнения.

В этом примере проверяется связь с 4 серверами имен и регистрируется самая быстрая 2 на консоли:

Promise.some([
    ping("ns1.example.com"),
    ping("ns2.example.com"),
    ping("ns3.example.com"),
    ping("ns4.example.com")
], 2).spread(function(first, second) {
    console.log(first, second);
});
0 голосов
/ 16 октября 2018

Вот что-то похожее на метод BlueBird Promise.some , предложенный @Neverever

function awaitSome(promises, count) {
    if (!Array.isArray(promises) || promises.length < count) {
        return Promise.reject();
    }

    return new Promise((resolve, reject) => {
        const results = [];
        const errors = [];
        let completed = false;

        promises.forEach((p) => {
            p.then((result) => {
                if (!completed) {
                    results.push(result);
                    if (results.length === count) {
                        completed = true;
                        resolve(results);
                    }
                }
            }).catch((err) => {
                if (!completed) {
                    errors.push(err);
                    if (promises.length - errors.length < count) {
                        completed = true;
                        reject(errors);
                    }
                }
            });
        });
    });
}

И использование может быть

awaitSome(
    [
        Promise.resolve(1),
        Promise.reject(1),
        Promise.resolve(1),
        Promise.resolve(1)
    ],
    2
)
    .then((results) => {
        console.log(results);
    })
    .catch((errors) => {
        console.error(errors);
    });
0 голосов
/ 16 октября 2018

Вы можете создать два Promises и поместить их resolve в массив.Когда один ответ возвращается, pop() один из resolve s и позвоните ему.Повторите для второго ответа.Дальнейшие ответы можно игнорировать, поскольку массив теперь пуст.

Затем вы можете вызвать Promise.all для двух построенных Обещаний, которые разрешатся, когда будут вызваны оба resolve s.

const api = () => new Promise(res => {
  const timeout = Math.random() * 3000;
  setTimeout(() => {
    console.log('resolving ' + timeout);
    res(timeout);
  }, timeout)
});

const resolves = [];
const prom1 = new Promise(resolve => resolves.push(resolve));
const prom2 = new Promise(resolve => resolves.push(resolve));

for (let i = 0; i < 10; i++) {
  api().then(res => {
    if (!resolves.length) return;
    resolves.pop()(res);
  });
}
Promise.all([prom1, prom2])
  .then(([res1, res2]) => {
    console.log('got 2 responses', res1, res2);
  });

Как видно из приведенного выше кода, хотя последние вызовы API с 3 по 10 разрешаются, Promise.all разрешается, как только первое и второе самое быстрое решение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...