it-swarm.com.de

Rufen Sie parallel async / await-Funktionen auf

Soweit ich weiß, funktioniert es in ES7/ES2016 ähnlich, mehrere await in Code zu setzen, wie .then() mit Versprechungen zu verketten, was bedeutet, dass sie nacheinander und nicht in parallerl ausgeführt werden. So haben wir zum Beispiel diesen Code:

await someCall();
await anotherCall();

Verstehe ich es richtig, dass anotherCall() nur aufgerufen wird, wenn someCall() abgeschlossen ist? Was ist die eleganteste Art, sie parallel zu nennen?

Ich möchte es in Node verwenden, gibt es also möglicherweise eine Lösung mit einer asynchronen Bibliothek?

BEARBEITEN: Ich bin mit der Lösung in dieser Frage nicht zufrieden: Verlangsamung aufgrund nicht parallelen Wartens auf Versprechungen in Async-Generatoren , weil es Generatoren verwendet und ich nach einem allgemeineren Anwendungsfall frage .

308
Victor Marchuk

Sie können auf Promise.all() warten:

await Promise.all([someCall(), anotherCall()]);

So speichern Sie die Ergebnisse:

let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
492
madox2

TL; DR

Verwenden Sie Promise.all für die parallelen Funktionsaufrufe. Das Antwortverhalten ist nicht korrekt, wenn der Fehler auftritt.


Führen Sie zuerst alle asynchronen Aufrufe auf einmal aus und erhalten Sie alle Promise -Objekte. Verwenden Sie zweitens await für die Promise Objekte. Während Sie auf das erste Promise warten, um die anderen asynchronen Aufrufe aufzulösen, werden diese weiterhin ausgeführt. Insgesamt warten Sie nur so lange wie der langsamste asynchrone Anruf. Zum Beispiel:

// Begin first call and store promise without waiting
const someResult = someCall();

// Begin second call and store promise without waiting
const anotherResult = anotherCall();

// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];

// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise

JSbin-Beispiel: http://jsbin.com/xerifanima/edit?js,console

Vorsichtsmaßnahme: Es spielt keine Rolle, ob die await -Anrufe auf derselben Leitung oder auf verschiedenen Leitungen liegen, solange die ersten await Aufruf erfolgt nach allen asynchronen Aufrufen. Siehe den Kommentar von JohnnyHK.


Update: Diese Antwort hat ein anderes Timing bei der Fehlerbehandlung als die @ bergis Antwort , das tut sie NOT wirft den Fehler aus, wenn der Fehler auftritt, aber nachdem alle Versprechungen ausgeführt wurden. Ich vergleiche das Ergebnis mit @ jonnys Tipp: [result1, result2] = Promise.all([async1(), async2()]), überprüfe den folgenden Codeausschnitt

const correctAsync500ms = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 500, 'correct500msResult');
  });
};

const correctAsync100ms = () => {
  return new Promise(resolve => {
    setTimeout(resolve, 100, 'correct100msResult');
  });
};

const rejectAsync100ms = () => {
  return new Promise((resolve, reject) => {
    setTimeout(reject, 100, 'reject100msError');
  });
};

const asyncInArray = async (fun1, fun2) => {
  const label = 'test async functions in array';
  try {
    console.time(label);
    const p1 = fun1();
    const p2 = fun2();
    const result = [await p1, await p2];
    console.timeEnd(label);
  } catch (e) {
    console.error('error is', e);
    console.timeEnd(label);
  }
};

const asyncInPromiseAll = async (fun1, fun2) => {
  const label = 'test async functions with Promise.all';
  try {
    console.time(label);
    let [value1, value2] = await Promise.all([fun1(), fun2()]);
    console.timeEnd(label);
  } catch (e) {
    console.error('error is', e);
    console.timeEnd(label);
  }
};

(async () => {
  console.group('async functions without error');
  console.log('async functions without error: start')
  await asyncInArray(correctAsync500ms, correctAsync100ms);
  await asyncInPromiseAll(correctAsync500ms, correctAsync100ms);
  console.groupEnd();

  console.group('async functions with error');
  console.log('async functions with error: start')
  await asyncInArray(correctAsync500ms, rejectAsync100ms);
  await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms);
  console.groupEnd();
})();
96
Haven

pdate:

Die ursprüngliche Antwort macht es schwierig (und in einigen Fällen unmöglich), Versprechungsablehnungen richtig zu handhaben. Die richtige Lösung ist die Verwendung von Promise.all:

const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);

rsprüngliche Antwort:

Stellen Sie einfach sicher, dass Sie beide Funktionen aufrufen, bevor Sie eine abwarten:

// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();

// Await both promises    
const someResult = await somePromise;
const anotherResult = await anotherPromise;
79
Jonathan Potter

Es gibt einen anderen Weg ohne Promise.all (), dies parallel zu tun:

Erstens haben wir 2 Funktionen zum Drucken von Zahlen:

function printNumber1() {
   return new Promise((resolve,reject) => {
      setTimeout(() => {
      console.log("Number1 is done");
      resolve(10);
      },1000);
   });
}

function printNumber2() {
   return new Promise((resolve,reject) => {
      setTimeout(() => {
      console.log("Number2 is done");
      resolve(20);
      },500);
   });
}

Dies ist sequentiell:

async function oneByOne() {
   const number1 = await printNumber1();
   const number2 = await printNumber2();
} 
//Output: Number1 is done, Number2 is done

Dies ist parallel:

async function inParallel() {
   const promise1 = printNumber1();
   const promise2 = printNumber2();
   const number1 = await promise1;
   const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
15
user2883596

Ich habe a Gist erstellt, um verschiedene Möglichkeiten zum Lösen von Versprechungen mit Ergebnissen zu testen. Es kann hilfreich sein, die Optionen zu überprüfen, die funktionieren.

6
SkarXa
    // A generic test function that can be configured 
    // with an arbitrary delay and to either resolve or reject
    const test = (delay, resolveSuccessfully) => new Promise((resolve, reject) => setTimeout(() => {
        console.log(`Done ${ delay }`);
        resolveSuccessfully ? resolve(`Resolved ${ delay }`) : reject(`Reject ${ delay }`)
    }, delay));

    // Our async handler function
    const handler = async () => {
        // Promise 1 runs first, but resolves last
        const p1 = test(10000, true);
        // Promise 2 run second, and also resolves
        const p2 = test(5000, true);
        // Promise 3 runs last, but completes first (with a rejection) 
        // Note the catch to trap the error immediately
        const p3 = test(1000, false).catch(e => console.log(e));
        // Await all in parallel
        const r = await Promise.all([p1, p2, p3]);
        // Display the results
        console.log(r);
    };

    // Run the handler
    handler();
    /*
    Done 1000
    Reject 1000
    Done 5000
    Done 10000
    */

Während p1, p2 und p3 nicht unbedingt parallel laufen, halten sie keine Ausführung auf und Sie können kontextbezogene Fehler mit einem catch abfangen.

1
Thrunobulax