Anleitung zur Implementierung einer Promise-basierten API
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 implementiert, die promises
zurückgeben. Dies ist eine viel weniger häufige Aufgabe als die Verwendung von promise-basierten APIs, aber es ist trotzdem wissenswert.
Voraussetzungen: | Ein fundiertes Verständnis der JavaScript-Grundlagen und asynchroner Konzepte, wie sie in den vorherigen Lektionen dieses Moduls behandelt wurden. |
---|---|
Lernziele: | Verstehen, wie man promise-basierte APIs implementiert. |
Im Allgemeinen werden Sie bei der Implementierung einer Promise-basierten API eine asynchrone Operation umschließen, die Events, einfache Callbacks oder ein Nachrichtenübertragungsmodell verwenden könnte. Sie werden ein Promise
-Objekt arrangieren, das den Erfolg oder das Scheitern dieser Operation ordnungsgemäß handhabt.
Implementierung einer alarm()
API
In diesem Beispiel implementieren wir eine promise-basierte Alarm-API, genannt alarm()
. Sie wird als Argumente den Namen der Person, die geweckt werden soll, und eine Verzögerung in Millisekunden entgegennehmen, bevor die Person geweckt wird. Nach der Verzögerung sendet die Funktion eine "Wake up!"-Nachricht, einschließlich des Namens der Person, die wir wecken müssen.
Einwickeln von setTimeout()
Wir verwenden die setTimeout()
API, um unsere alarm()
Funktion zu implementieren. Die setTimeout()
API nimmt als Argumente eine Callback-Funktion und eine Verzögerung in Millisekunden entgegen. Wenn setTimeout()
aufgerufen wird, startet es einen Timer, der auf die gegebene Verzögerung eingestellt ist, und wenn die Zeit abläuft, ruft es die gegebene Funktion auf.
Im folgenden Beispiel 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 gibt ein Promise
zurück, das erfüllt wird, wenn der Timer abläuft. Es wird eine "Wake up!"-Nachricht an den then()
-Handler übergeben und das Promise wird abgelehnt, wenn der Aufrufer einen negativen Verzögerungswert liefert.
Das Kernstück 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, geben Sie die Implementierung des Executors an.
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 wirft, wird reject
automatisch aufgerufen. Sie können einen einzigen Parameter beliebigen Typs an resolve
und reject
übergeben.
Daher können wir alarm()
so 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. Im Executor für das Promise:
-
prüfen wir, dass
delay
nicht negativ ist, und rufenreject
auf, wobei wir einen benutzerdefinierten Fehler übergeben, wenn dies der Fall ist. -
rufen wir
setTimeout()
auf, mit einem Callback unddelay
. Der Callback wird aufgerufen, wenn der Timer abläuft, und im Callback rufen wirresolve
auf, wobei wir unsere "Wake up!"-Nachricht übergeben.
Verwendung der alarm()
API
Dieser Teil sollte Ihnen aus dem letzten Artikel ziemlich bekannt vorkommen. 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, unterschiedliche 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 damit alles machen, was wir mit jedem anderen Promise tun könnten: Verkettung von Promises, 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}`;
}
});