async/await/promise

Die asynchrone Programmierung erlaubt es einem Programm, verschiedene Aufgaben parallel zu erledigen. Der Code kann nebeneinander ablaufen und muss nicht auf die Beendigung des vorherigen Codes warten. Dabei ist das Promise-Objekt von entscheidender Bedeutung:

Das Promise-Objekt (dt./deutsch Ein Versprechens-Objekt, das später eingelöst wird) wird für asynchrone Berechnungen verwendet.

Bei der asynchronen Programmierung gibt es also ein Promise, ein Versprechen, dass zum Beispiel Daten vom Server geladen werden. Dieses Versprechen kann dann wieder genutzt werden, um zu prüfen ob es fertig ist und ob alles funktioniert hat, also das Versprechen eingehalten wurde.

Oft wird die asynchrone Programmierung bei externen Ressourcenzugriffen automatisch genutzt, wenn du zum Beispiel eine Datei vom Server lädst.

fetch("./data/data1.json")
    .then(response => response.json())
    .then(data => console.log(data));
console.log("Daten geladen?");

Hier wird die Datei data1.json vom Server geladen. Die Methode fetch() läuft asynchron und erstellt ein Promise-Objekt. Das heißt, dass das Laden startet und dann sofort der Code darunter weiter ausgeführt wird. Also bevor die Datei vom Server fertig geladen wurde, wird im Programm „Daten geladen?“ ausgegeben.

Willst du die Ausgabe erst nach dem Laden der Datei anzeigen kannst du die .then() Methode nutzen, die erst ausgeführt wird, wenn die asynchrone Methode fertig ist. Hinter den Kulissen wird auf das Promise-Objekt gewartet:

fetch("./data/data1.json")
    .then(response => response.json())
    .then(data => {
		console.log(data);
		console.log("Daten geladen!");
	});

setTimeout()

Mit der setTimeout() Methode kannst du die Ausführung von Code eine gewisse Zeit verzögern:

setTimeout(() => {
  console.log('World')
}, 1000);

console.log('Hello');

Hier wird zum Beispiel sofort „Hello“ in die Konsole geschrieben und erst nach 1 Sekunde das Wort „World“.

Willst du mit der ganzen Programmausführung warten bis eine gewisse Zeit verstrichen ist, kannst du die setTimeout() Methode in einen Promise packen und dann in einer asynchronen Funktion aufrufen:

const myTimeout = function(delay) {
   return new Promise(resolve => setTimeout(resolve, delay));
}

async function myFunction(){
  console.log("Hello ");
  await myTimeout(1000);
  console.log("World");
}

myFunction();

Den await Befehl kannst du nur in einer asynchronen Funktion nutzen um auf einen Promise zu warten. Darum habe ich die Funktion myFunction() erstellt und den Code dort eingetragen. Hier wird sofort „Hello“ in die Konsole geschrieben, dann 1 Sekunde gewartet und dann der Code darunter ausgeführt, also console.log(„World“);.

Animationen

Auch die meisten Animationen laufen asynchron ab, also parallel nebeneinander. Willst du aber eine Animation abspielen nachdem eine erste Animation fertig ist benötigst du auch den Promise und kannst mit Hilfe von await oder .then() warten bis dieser erfüllt wurde.

Im folgenden Beispiel soll eine Attack-Animation gespielt werden, dann der Angreifer getauscht werden und dann nochmal die Attack-Animation in vertauschten Rollen gespielt werden. Wir warten also bis die erste Animation fertig ist, dann tauschen wir die Rollen und spielen die Animation erneut:

async function startBattle(attacker, target) {
    await this.attackTarget();
    this.changeAttacker();
    await this.attackTarget();
}

Hier die attackTarget() Methode. Die Variable attackAnimation_1 bekommt einen Promise und auf diesen Promise wird danach gewartet: await attackAnimation_1;

async function attackTarget() {

    const attackAnimation_1 = anime({
      targets: "#" + this.props.attacker.elementId,
      scaleX: scaleX,
      translateX: translateX,
      translateY: translateY,
      rotate: rotate,
      duration: 500,
      complete: function () {
        self.hitTarget();
      },
    }).finished;

    await attackAnimation_1;

    const attackAnimation_2 = anime({
      targets: "#" + this.props.attacker.elementId,
      translateX: 0,
      translateY: 0,
      rotate: 0,
      duration: 500,
      complete: function () {
        self.attackFinished();
      },
    }).finished;

    await attackAnimation_2;
}

Externe Ressourcen laden

Will man zum Beispiel mehrere JSON Dateien hintereinander laden kann man die Funktionen aneinanderreihen:

fetch("./data/data1.json")
    .then(response => response.json())
    .then(data => console.log(data))
    .then(() => {
        fetch("./data/data2.json")
            .then(response => response.json())
            .then(data => console.log(data))
    });

Eine weitere Möglichkeit ist es die fetch Funktion in eine andere Funktion zu implementieren. Da fetch einen Promise zurückgibt, muss auch die neue Methode eine async Methode sein:

async function loadJsonData(jsonFile) {
    fetch(jsonFile)
        .then(response => response.json())
        .then(data => console.log(data));
}

loadJsonData("./data/data1.json")
    .then(loadJsonData("./data/data2.json"));

In diesem Beispiel werden mit Hilfe einer PHP-Datei Daten aus einer Datenbank abgefragt.

import axios from "axios";

export const getTextsFromDB = async () => {
	const urlDatabaseGetTextTitles = "http://127.0.0.1/php/get_text_titles.php";

	const res = await axios
		.post(urlDatabaseGetTextTitles)
		.then(function (response) {
			return response.data;
		})
		.catch(function (error) {
			console.log(error);
		});

	return res;
};

Diese Methode kann dann importiert und von anderer Stelle im Programm aufgerufen werden:

//load texts from DB once per page load
useEffect(() => {
	getTextsFromDB().then(function (responseData) {
		fillTextList(responseData);
		getTextFromDB(responseData[0].code);
	});
}, []);

unsere-schule.org

×

async/await/promise

Code: