web-dev-qa-db-ger.com

Wie kann ich async/await auf der obersten Ebene verwenden?

Ich bin async/waited durchgegangen und nach mehreren Artikeln habe ich mich entschieden, die Dinge selbst zu testen. Ich kann mich jedoch scheinbar nicht darum kümmern, warum das nicht funktioniert:

async function main() {  
    var value = await Promise.resolve('Hey there');
    console.log('inside: ' + value);
    return value;
}

var text = main();  
console.log('outside: ' + text)

Die Konsole gibt Folgendes aus (Knoten v8.6.0):

> außerhalb: [Objekt Versprechen]

> innen: Hey da

Warum wird die Protokollnachricht in der Funktion anschließend ausgeführt? Ich dachte, der Grund, warum async/await geschaffen wurde, war die synchrone Ausführung mit asynchronen Tasks.

Gibt es eine Möglichkeit, den in der Funktion zurückgegebenen Wert ohne .then() nach main() zu verwenden?

56
Felipe

Ich kann meinen Kopf nicht umwickeln, warum das nicht funktioniert.

Weil main ein Versprechen zurückgibt. Alle async-Funktionen tun dies.

Auf der obersten Ebene müssen Sie entweder:

  1. Verwenden Sie eine async-Funktion der obersten Ebene, die niemals ablehnt, oder

  2. Verwenden Sie then und catch

# 1 - Die oberste async-Funktion, die niemals ablehnt

(async () => {
    try {
        var text = await main();
        console.log(text);
    } catch (e) {
        // Deal with the fact the chain failed
    }
})();

Beachten Sie das catch; Sie must behandeln Versagensverweigerungen/asynchrone Ausnahmen, da sonst nichts weitergeht; Sie haben keinen Anrufer, an den sie weitergeleitet werden können. Wenn Sie möchten, können Sie dies auch mit dem Ergebnis des Aufrufs über die catch-Funktion (anstelle der try/catch-Syntax) tun:

(async () => {
    var text = await main();
    console.log(text);
})().catch(e => {
    // Deal with the fact the chain failed
});

... was etwas prägnanter ist (ich mag es deshalb).

# 2 - then und catch

main()
    .then(text => {
        console.log(text);
    })
    .catch(err => {
        // Deal with the fact the chain failed
    });

Der catch-Handler wird aufgerufen, wenn Fehler in der Kette oder in Ihrem then-Handler auftreten. (Stellen Sie sicher, dass Ihr catch-Handler keine Fehler auslöst, da nichts registriert ist, um ihn zu behandeln.)

Oder beide Argumente für then:

main().then(
    text => {
        console.log(text);
    },
    err => {
        // Deal with the fact the chain failed
    }
);

Nochmals beachten wir, dass wir einen Ablehnungs-Handler registrieren. Stellen Sie jedoch in dieser Form sicher, dass keiner Ihrer then-Callbacks keine Fehler auslöst, und es ist nichts registriert, um damit umzugehen.

87
T.J. Crowder

Top-Level await ist zu Stufe 3 übergegangen, daher die Antwort auf Ihre Frage Wie kann ich async/await auf der obersten Ebene verwenden? fügt einfach await den Aufruf zu main() hinzu:

async function main() {  
    var value = await Promise.resolve('Hey there');
    console.log('inside: ' + value);
    return value;
}

var text = await main();  
console.log('outside: ' + text)

Oder nur:

const text = await Promise.resolve('Hey there');
console.log('outside: ' + text)

Denken Sie daran, dass es immer noch nur in [email protected] verfügbar ist.

2
lautaro.dragan

Die eigentliche Lösung für dieses Problem besteht darin, es anders anzugehen.

Ihr Ziel ist wahrscheinlich eine Art Initialisierung, die normalerweise auf der obersten Ebene einer Anwendung stattfindet.

Die Lösung besteht darin, sicherzustellen, dass es nur eine einzige JavaScript-Anweisung auf der obersten Ebene Ihrer Anwendung gibt. Wenn Sie nur eine Anweisung oben in Ihrer Anwendung haben, können Sie Async/await an jedem beliebigen anderen Ort verwenden (natürlich vorbehaltlich normaler Syntaxregeln).

Um es anders auszudrücken, wickeln Sie Ihre gesamte oberste Ebene in eine Funktion ein, sodass diese nicht mehr die oberste Ebene ist und sich damit die Frage löst, wie async/await auf der obersten Ebene einer Anwendung ausgeführt wird.

So sollte die oberste Ebene Ihrer Anwendung aussehen:

import {application} from './server'

application();
2
Duke Dougal

Um weitere Informationen zu den aktuellen Antworten zu geben:

Der Inhalt einer node.js-Datei wird derzeit stringartig zu einem Funktionskörper verkettet.

Zum Beispiel, wenn Sie eine Datei test.js haben:

// Amazing test file!
console.log('Test!');

Dann verkettet node.js eine Funktion, die wie folgt aussieht:

function(require, __dirname, ... a bunch more top-level properties) {
  // Amazing test file!
  console.log('test!');
}

Das Wichtigste ist, dass die resultierende Funktion KEINE asynchrone Funktion ist. Sie können also den Begriff await nicht direkt darin verwenden!

Angenommen, Sie müssen mit Versprechen in dieser Datei arbeiten. Dann gibt es zwei mögliche Methoden:

  1. Verwenden Sie nicht await direkt innerhalb der Funktion
  2. Verwenden Sie nicht await

Bei Option 1 müssen wir einen neuen Gültigkeitsbereich erstellen (und dieser Gültigkeitsbereich kann async sein, da wir die Kontrolle darüber haben):

// Amazing test file!
// Create a new async function (a new scope) and immediately call it!
(async () => {
  await new Promise(...);
  console.log('Test!');
})();

Option 2 erfordert die Verwendung der objektorientierten Versprechen-API (das weniger hübsche, aber ebenso funktionale Paradigma der Arbeit mit Versprechen).

// Amazing test file!
// Create some sort of promise...
let myPromise = new Promise(...);

// Now use the object-oriented API
myPromise.then(() => console.log('Test!'));

Ich persönlich hoffe, dass node.js, wenn es funktioniert, standardmäßig Code in einer async-Funktion verkettet. Das würde diese Kopfschmerzen loswerden.

1
Gershom Maes

Da main() asynchron läuft, wird ein Versprechen zurückgegeben. Sie müssen das Ergebnis in der then()-Methode erhalten. Und da then() auch Versprechen zurückgibt, müssen Sie process.exit() aufrufen, um das Programm zu beenden. 

main()
   .then(
      (text) => { console.log('outside: ' + text) },
      (err)  => { console.log(err) }
   )
   .then(() => { process.exit() } )
0
Peracek