Wie man eine Promise-basierte API implementiert
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 viel seltener ausgeführte Aufgabe als die Verwendung von Promise-basierten APIs, aber dennoch wissenswert.
Voraussetzungen: | Ein solides Verständnis der JavaScript-Grundlagen und asynchroner Konzepte, wie sie in den vorhergehenden Lektionen dieses Moduls behandelt wurden. |
---|---|
Lernziele: | Verstehen, wie Promise-basierte APIs implementiert werden. |
Im Allgemeinen, wenn Sie eine Promise-basierte API implementieren, werden Sie eine asynchrone Operation umhüllen, die Ereignisse, einfache Callback-Funktionen oder ein Nachrichtenübertragungsmodell verwenden könnte. Sie werden ein Promise
-Objekt arrangieren, um den Erfolg oder Fehler dieser Operation korrekt zu behandeln.
Implementieren einer alarm()
API
In diesem Beispiel werden wir eine Promise-basierte Alarm-API implementieren, die alarm()
genannt wird. Sie wird als Argumente den Namen der Person, die geweckt werden soll, und eine Verzögerung in Millisekunden annehmen, bevor die Person geweckt wird. Nach der Verzögerung wird die Funktion eine "Wake up!"-Nachricht senden, einschließlich des Namens der Person, die geweckt werden muss.
Umhüllen von setTimeout()
Wir werden die setTimeout()
API verwenden, um unsere alarm()
-Funktion zu implementieren. Die setTimeout()
API nimmt als Argumente eine Callback-Funktion und eine Verzögerung in Millisekunden. Wenn setTimeout()
aufgerufen wird, startet es einen Timer auf die gegebene Verzögerung eingestellt, und wenn diese Zeit abläuft, ruft es die gegebene Funktion auf.
Im Beispiel unten rufen wir setTimeout()
mit einer Callback-Funktion 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 "Wake up!"-Nachricht in den then()
-Handler übergeben und das Promise ablehnen, wenn der Aufrufer einen negativen Verzögerungswert übergibt.
Der Schlüsselfaktor hier ist der Promise()
Konstruktor. Der Promise()
Konstruktor nimmt eine einzige Funktion als Argument. Wir nennen diese Funktion den executor
. Wenn Sie ein neues Promise erstellen, liefern Sie die Implementierung des Executors.
Diese Executor-Funktion nimmt selbst zwei Argumente an, die beide ebenfalls Funktionen sind und 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 wirft, wird reject
automatisch aufgerufen. In resolve
und reject
können Sie einen einzelnen Parameter jeglichen Typs übergeben.
So können wir alarm()
wie folgt 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:
-
prüfen wir, ob
delay
nicht negativ ist, und rufenreject
auf, wobei wir einen benutzerdefinierten Fehler übergeben, wenn dies der Fall ist. -
rufen wir
setTimeout()
auf, übergeben ein Callback unddelay
. Das Callback wird aufgerufen, wenn der Timer abläuft, und im Callback rufen wirresolve
auf und übergeben unsere "Wake up!
" Nachricht.
Verwenden der alarm()
API
Dieser Teil sollte aus dem letzten Artikel recht 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 "Delay" einzustellen. Versuchen Sie, einen negativen Wert für "Delay" einzustellen.
Verwenden von async und await mit der alarm()
API
Da alarm()
ein Promise
zurückgibt, können wir alles mit ihm tun, was wir mit jedem anderen Promise tun 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"));
}
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}`;
}
});