Anleitung zur Implementierung einer auf Promises basierenden API
Im letzten Artikel haben wir besprochen, wie man APIs verwendet, die Promises zurückgeben. In diesem Artikel betrachten wir die andere Seite – wie man APIs implementiert, die Promises zurückgeben. Dies ist eine deutlich seltenere Aufgabe als die Verwendung auf Promises basierender APIs, aber es ist dennoch wissenswert.
Voraussetzungen: | Ein angemessenes Verständnis der grundlegenden JavaScript-Konzepte, einschließlich der Ereignisbehandlung und der Grundlagen von Promises. |
---|---|
Ziel: | Zu verstehen, wie man auf Promises basierende APIs implementiert. |
Im Allgemeinen wird bei der Implementierung einer auf Promises basierenden API eine asynchrone Operation umschlossen, die Ereignisse, einfache Rückrufmethoden oder ein Nachrichtenaustauschmodell verwenden könnte. Sie organisieren ein Promise
-Objekt, um den Erfolg oder das Scheitern dieser Operation ordnungsgemäß zu behandeln.
Implementierung einer alarm()
API
In diesem Beispiel implementieren wir eine auf Promises basierende Alarm-API, genannt alarm()
. Sie nimmt als Argumente den Namen der aufzuweckenden Person und eine Verzögerung in Millisekunden, bevor die Person geweckt wird. Nach der Verzögerung sendet die Funktion eine "Aufwachen!"-Nachricht, einschließlich des Namens der Person, die aufgeweckt werden muss.
Verwendung von setTimeout()
Wir verwenden die setTimeout()
API, um unsere alarm()
-Funktion zu implementieren. Die setTimeout()
API nimmt als Argumente eine Rückruffunktion und eine Verzögerung in Millisekunden. Wenn setTimeout()
aufgerufen wird, startet es einen Timer, der auf die angegebene Verzögerung eingestellt ist, und ruft bei Ablauf der Zeit die gegebene Funktion auf.
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 Promise() Konstruktor
Unsere alarm()
-Funktion wird ein Promise
zurückgeben, das erfüllt wird, wenn der Timer abläuft. Es wird eine "Aufwachen!"-Nachricht an den then()
-Handler übergeben und das Promise ablehnen, wenn der Aufrufer 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, die beide ebenfalls 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 fehlschlägt, rufen Sie reject
auf. Wenn die Executor-Funktion einen Fehler auslöst, wird reject
automatisch aufgerufen. Sie können einen einzelnen Parameter beliebigen Typs in resolve
und reject
übergeben.
So können wir alarm()
implementieren:
function alarm(person, delay) {
return new Promise((resolve, reject) => {
if (delay < 0) {
reject(new Error("Alarm delay must not be negative"));
}
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, ob
delay
nicht negativ ist, und rufenreject
mit einem benutzerdefinierten Fehler auf, wenn dies der Fall ist. -
Rufen wir
setTimeout()
auf, übergeben einen Rückruf unddelay
. Der Rückruf wird aufgerufen, wenn der Timer abläuft, und im Rückruf rufen wirresolve
auf und übergeben unsere"Aufwachen!"
-Nachricht.
Verwendung der alarm() API
Dieser Teil sollte Ihnen aus dem letzten Artikel vertraut sein. Wir können alarm()
aufrufen und auf dem zurückgegebenen Promise then()
und catch()
aufrufen, um Handler für die Erfüllung und Ablehnung des Promises festzulegen.
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"));
}
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 "Verzögerung" zu setzen. Versuchen Sie, einen negativen Wert für "Verzögerung" zu setzen.
Verwendung von async und await mit der alarm() API
Da alarm()
ein Promise
zurückgibt, können wir alles damit machen, was wir mit jedem anderen Promise tun könnten: Promise-Chaining, 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"));
}
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}`;
}
});