Promise.all Замена? - PullRequest
       30

Promise.all Замена?

4 голосов
/ 10 октября 2019

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

Я уже использую Promise.allдля нескольких асинхронных вызовов, но дает ответы, когда все вызовы завершены.

Ответы [ 4 ]

2 голосов
/ 10 октября 2019

Вы можете просто перебрать массив обещаний и изменить состояние для каждого разрешения обещания:

let state = null;

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({p1: 1});
  }, 2000);
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({p2: 2});
  }, 1000);
});
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve({p3: 3});
  }, 3000);
});

// Iterate promises
[p1, p2, p3].forEach(p => {
  p.then(res => {
    state = Object.assign({}, state, res);
    console.log(state);
  });
});

console.log(state);

Вы можете создать свой собственный метод Promise для этой задачи:

if (!Promise.each) {
  Promise.each = function(promises, callback, error) {
    if (promises && Array.isArray(promises)) {
      promises.forEach(p => {
        p.then(res => {
          callback(res);
        }, err => {
          if (error) {
              error(err);
          } else {
              console.log(err);
          }          
        });
      });
    }
  }
}

// Usage
Promise.each([p1, p2, p3], updateState);
1 голос
/ 10 октября 2019

Пока вы не используете async / await, вы можете выполнять вызовы параллельно. Обратите внимание, что браузеры имеют ограничение на количество сетевых запросов, поэтому если вы выполняете, например, 100 вызовов, они не будут параллельными, а будут поставлены в очередь.

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

function resolved(data) {
    // ...
}

const promise1 = new Promise(function(resolve, reject) {
    resolve('Success!');
}).then(resolved);

const promise2 = new Promise(function(resolve, reject) {
    resolve('Success!');
}).then(resolved);
0 голосов
/ 10 октября 2019

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

async function f1(){ await Promise.resolve(); }
async funciton f2(){ await Promise.resolve(); }
async function fn(){ await Promise.resolve(); }

async function drvAsync(){
  const [r1, r2, rn] = await Promise.all([f1(), f2(), fn()]);
  u1(r1);
  u2(r2);
  un(rn);
}

, где f [n] - асинхронная бизнес-функция, а u [n] - метод для обработки результата, полученного в результате. Эта схема не приемлема в вашем сценарии. Возможно, fn завершается быстрее, чем другие, и вы хотите обновить N-е состояние раньше.

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

function drv(){
  f1().then((r1)=>u1(r1)).catch((e)=>er(e));
  f2().then((r2)=>u2(r2)).catch((e)=>er(e));
  fn().then((rn)=>un(rn)).catch((e)=>er(e));;  
}

Эта схема будет вызывать каждый метод обновления (u [n]), не ожидая результатов от других.

0 голосов
/ 10 октября 2019

Это то, для чего Promise.race:

Метод Promise.race() возвращает обещание, которое выполняется или отклоняется, как только одно из обещаний в итерируемом выполнении выполняетсяили отклоняет, со значением или причиной этого обещания.

Например:

function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function main() {
  const promises = [
    sleep(1000).then(() => "world"),
    sleep(100).then(() => "hello"),
  ];
  const promisesWithIndices = promises.map((p, index) =>
    p.then((result) => ({result, index}))
  );
  while (promisesWithIndices.length > 0) {
    const {result, index} = await Promise.race(promisesWithIndices);
    console.log("%s -> %s", index, result);
    promisesWithIndices.splice(index, 1);
  }
}

main();  // prints "1 -> hello"; then prints "0 -> world" after a while
...