Umsetzung einer API auf Basis von Promises
Im letzten Artikel haben wir besprochen, wie man APIs nutzt, die Promises zurückgeben. In diesem Artikel schauen wir uns die andere Seite an – wie man APIs umsetzt, die Promises zurückgeben. Diese Aufgabe ist viel seltener als die Nutzung von auf Promises basierenden APIs, aber es ist dennoch wertvoll, darüber Bescheid zu wissen.
Voraussetzungen: | Ein solides Verständnis von JavaScript-Grundlagen und asynchronen Konzepten, wie sie in den vorherigen Lektionen dieses Moduls behandelt wurden. |
---|---|
Lernergebnisse: | Verstehen, wie man APIs auf Basis von Promises umsetzt. |
Im Allgemeinen werden Sie, wenn Sie eine API mit Promises umsetzen, eine asynchrone Operation umhüllen, die Ereignisse verwenden könnte, einfache Rückruffunktionen oder ein Nachrichtenübermittlungsmodell. Sie arrangieren ein Promise
-Objekt, um den Erfolg oder das Scheitern dieser Operation korrekt zu handhaben.
Umsetzung einer alarm()
API
In diesem Beispiel implementieren wir eine Alarm-API auf Basis von Promises, genannt alarm()
. Die Funktion nimmt als Argumente den Namen der Person, die geweckt werden soll, und eine Verzögerung in Millisekunden, bevor die Person geweckt werden soll. Nach der Verzögerung sendet die Funktion eine "Wake up!"-Nachricht, die den Namen der Person enthält, die geweckt werden muss.
Umhüllung von setTimeout()
Wir verwenden die API setTimeout()
, um unsere alarm()
-Funktion zu implementieren. Die setTimeout()
-API nimmt als Argumente eine Rückruffunktion und eine Verzögerung, angegeben in Millisekunden. Wenn setTimeout()
aufgerufen wird, startet es einen Timer, der auf die gegebene Verzögerung eingestellt ist, und wenn die Zeit abläuft, wird die gegebene Funktion aufgerufen.
Im folgenden Beispiel rufen wir setTimeout()
mit einer Rückruffunktion und einer Verzögerung von 1000 Millisekunden auf:
<button id="set-alarm">Set alarm</button>
<div id="output"></div>
const output = document.querySelector("#output");
const button = document.querySelector("#set-alarm");
function setAlarm() {
setTimeout(() => {
output.textContent = "Wake up!";
}, 1000);
}
button.addEventListener("click", setAlarm);
Der Konstruktor Promise()
Unsere alarm()
-Funktion wird ein Promise
zurückgeben, das erfüllt wird, wenn der Timer abläuft. Es wird eine "Wake up!"-Nachricht in den then()
-Handler übergeben und das Promise ablehnen, wenn der Anrufer einen negativen Verzögerungswert angibt.
Der entscheidende Bestandteil hier ist der Promise()
-Konstruktor. Der Promise()
-Konstruktor nimmt eine einzelne Funktion als Argument. Wir nennen diese Funktion den executor
. Wenn Sie ein neues Promise erstellen, liefern Sie die Implementierung des Executors.
Diese Executor-Funktion selbst nimmt zwei Argumente entgegen, die beide auch Funktionen sind und die konventionell resolve
und reject
genannt werden. In Ihrer Executor-Implementierung rufen Sie die zugrunde liegende asynchrone Funktion auf. Wenn die asynchrone Funktion erfolgreich ist, rufen Sie resolve
auf und wenn sie scheitert, rufen Sie reject
auf. Wenn die Executor-Funktion einen Fehler wirft, wird reject
automatisch aufgerufen. Sie können ein einzelnes Argument eines beliebigen Typs an resolve
und reject
übergeben.
So können wir alarm()
wie folgt umsetzen:
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
reject(new Error("Alarm delay must not be negative"));
return;
}
setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
Diese Funktion erstellt und gibt ein neues Promise
zurück. Innerhalb des Executors für das Promise:
-
überprüfen wir, dass
delay
nicht negativ ist, und rufenreject
auf, wobei wir einen benutzerdefinierten Fehler übergeben, falls dies der Fall ist. -
rufen wir
setTimeout()
auf, übergeben eine Rückruffunktion unddelay
. Die Rückruffunktion wird aufgerufen, wenn der Timer abläuft, und in der Rückruffunktion rufen wirresolve
auf, wobei wir unsere "Wake up!"-Nachricht übergeben.
Nutzung der alarm()
-API
Dieser Abschnitt sollte Ihnen aus dem letzten Artikel bekannt vorkommen. Wir können alarm()
aufrufen und an dem zurückgegebenen Promise then()
und catch()
aufrufen, um Handler für die Erfüllung und Ablehnung des Promises einzurichten.
const name = document.querySelector("#name");
const delay = document.querySelector("#delay");
const button = document.querySelector("#set-alarm");
const output = document.querySelector("#output");
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
reject(new Error("Alarm delay must not be negative"));
return;
}
setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
button.addEventListener("click", () => {
alarm(name.value, delay.value)
.then((message) => (output.textContent = message))
.catch((error) => (output.textContent = `Couldn't set alarm: ${error}`));
});
Versuchen Sie, verschiedene Werte für "Name" und "Delay" festzulegen. Versuchen Sie, einen negativen Wert für "Delay" festzulegen.
Verwendung von async und await mit der alarm()
-API
Da alarm()
ein Promise
zurückgibt, können wir alles damit tun, was wir auch mit anderen Promises machen könnten: Promise-Verkettung, Promise.all()
und async
/ await
:
const name = document.querySelector("#name");
const delay = document.querySelector("#delay");
const button = document.querySelector("#set-alarm");
const output = document.querySelector("#output");
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
reject(new Error("Alarm delay must not be negative"));
return;
}
setTimeout(() => {
resolve(`Wake up, ${person}!`);
}, delay);
});
}
button.addEventListener("click", async () => {
try {
const message = await alarm(name.value, delay.value);
output.textContent = message;
} catch (error) {
output.textContent = `Couldn't set alarm: ${error}`;
}
});