Promise.prototype.then()
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Juli 2015 browserübergreifend verfügbar.
Die then()-Methode von Promise-Instanzen nimmt bis zu zwei Argumente: Callback-Funktionen für die erfüllten und abgelehnten Fälle des Promise. Sie speichert die Callbacks innerhalb des Promises, auf dem sie aufgerufen wird, und gibt sofort ein weiteres Promise-Objekt zurück, das es Ihnen ermöglicht, Aufrufe anderer Promise-Methoden zu verketteten.
Probieren Sie es aus
const promise1 = new Promise((resolve, reject) => {
resolve("Success!");
});
promise1.then((value) => {
console.log(value);
// Expected output: "Success!"
});
Syntax
then(onFulfilled)
then(onFulfilled, onRejected)
Parameter
onFulfilled-
Eine Funktion, die asynchron ausgeführt wird, wenn dieses Promise erfüllt wird. Der Rückgabewert wird zum Erfüllungswert des Promises, das von
then()zurückgegeben wird. Die Funktion wird mit den folgenden Argumenten aufgerufen:value-
Der Wert, mit dem das Promise erfüllt wurde.
Falls es keine Funktion ist, wird sie intern durch eine Identitätsfunktion (
(x) => x) ersetzt, die einfach den Erfüllungswert weitergibt. onRejectedOptional-
Eine Funktion, die asynchron ausgeführt wird, wenn dieses Promise abgelehnt wird. Der Rückgabewert wird zum Erfüllungswert des Promises, das von
then()zurückgegeben wird. Die Funktion wird mit den folgenden Argumenten aufgerufen:reason-
Der Wert, mit dem das Promise abgelehnt wurde.
Falls es keine Funktion ist, wird sie intern durch eine Thrower-Funktion (
(x) => { throw x; }) ersetzt, die den empfangenen Ablehnungsgrund wirft.
Rückgabewert
Gibt sofort ein neues Promise zurück. Dieses zurückgegebene Promise ist immer ausstehend, wenn es zurückgegeben wird, unabhängig vom Status des aktuellen Promises.
Einer der onFulfilled- und onRejected-Handler wird ausgeführt, um die Erfüllung oder Ablehnung des aktuellen Promises zu behandeln. Der Aufruf erfolgt immer asynchron, selbst wenn das aktuelle Promise bereits abgeschlossen ist. Das Verhalten des Promises, das von then() zurückgegeben wird (im Folgenden als p bezeichnet), hängt vom Ausführungsergebnis des Handlers ab und folgt einer spezifischen Regelmenge. Wenn die Handlerfunktion:
- einen Wert zurückgibt: wird
pmit dem zurückgegebenen Wert als seinem Wert erfüllt. - nichts zurückgibt: wird
pmitundefinedals seinem Wert erfüllt. - einen Fehler wirft: wird
pmit dem geworfenen Fehler als seinem Wert abgelehnt. - ein bereits erfülltes Promise zurückgibt: wird
pmit dem Wert dieses Promises als seinem Wert erfüllt. - ein bereits abgelehntes Promise zurückgibt: wird
pmit dem Wert dieses Promises als seinem Wert abgelehnt. - ein weiteres ausstehendes Promise zurückgibt: bleibt
pausstehend und wird mit dem Wert dieses Promises als seinem Wert erfüllt/abgelehnt, sobald dieses Promise erfüllt/abgelehnt wird.
Beschreibung
Die then()-Methode plant die Callback-Funktionen für den eventuellen Abschluss eines Promises — entweder Erfüllung oder Ablehnung. Es ist die primitive Methode von Promises: Das thenable-Protokoll erwartet, dass alle promisse-ähnlichen Objekte eine then()-Methode bereitstellen, und die catch()- und finally()-Methoden funktionieren beide durch Aufrufen der then()-Methode des Objekts.
Weitere Informationen zum onRejected-Handler finden Sie in der catch()-Referenz.
then() gibt ein neues Promise-Objekt zurück, verändert jedoch das Promise-Objekt, auf dem es aufgerufen wird, indem es die Handler zu einer internen Liste hinzufügt, wenn das Promise noch aussteht. Daher bleibt der Handler beim ursprünglichen Promise, solange dieses Promise ausstehend und erreichbar bleibt. Zum Beispiel wird das folgende Beispiel schließlich den Speicher erschöpfen, obwohl das zurückgegebene Promise nicht beibehalten wird:
const pendingPromise = new Promise(() => {});
while (true) {
pendingPromise.then(doSomething);
}
Wenn Sie die then()-Methode zweimal auf demselben Promise-Objekt aufrufen (anstatt zu verketten), wird dieses Promise-Objekt zwei Paare von Abwicklungs-Handlern haben. Alle an dasselbe Promise-Objekt angehängten Handler werden immer in der Reihenfolge aufgerufen, in der sie hinzugefügt wurden. Außerdem beginnen die beiden Promises, die von jedem Aufruf von then() zurückgegeben werden, separate Ketten und warten nicht auf die Abwicklung des jeweils anderen.
Thenable-Objekte, die entlang der then()-Kette entstehen, werden immer aufgelöst — der onFulfilled-Handler erhält niemals ein thenable-Objekt, und alle von einem Handler zurückgegebenen thenables werden immer aufgelöst, bevor sie an den nächsten Handler weitergegeben werden. Das liegt daran, dass beim Erstellen des neuen Promises die von dem Executor übergebenen resolve- und reject-Funktionen gespeichert werden, und wenn das aktuelle Promise abgeschlossen wird, die jeweilige Funktion mit dem Erfüllungswert oder dem Ablehnungsgrund aufgerufen wird. Die Auflösungslogik stammt von der resolve-Funktion, die vom Promise()-Konstruktor übergeben wird.
then() unterstützt Subclassing, was bedeutet, dass es auf Instanzen von Unterklassen von Promise aufgerufen werden kann, und das Ergebnis wird ein Promise des Subklasstyps sein. Sie können den Typ des Rückgabewertes über die [Symbol.species]-Eigenschaft anpassen.
Beispiele
>Verwendung der then()-Methode
const p1 = new Promise((resolve, reject) => {
resolve("Success!");
// or
// reject(new Error("Error!"));
});
p1.then(
(value) => {
console.log(value); // Success!
},
(reason) => {
console.error(reason); // Error!
},
);
Einen Nicht-Funktionstyp als Parameter haben
Promise.resolve(1).then(2).then(console.log); // 1
Promise.reject(new Error("failed")).then(2, 2).then(console.log, console.log); // Error: failed
Verkettung
Die then-Methode gibt ein neues Promise zurück, das es ermöglicht, Methoden zu verketten.
Wenn die als Handler an then übergebene Funktion ein Promise zurückgibt, wird ein entsprechendes Promise dem nachfolgenden then in der Methodenkette offengelegt. Der untenstehende Codeausschnitt simuliert asynchronen Code mit der setTimeout-Funktion.
Promise.resolve("foo")
// 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
.then(
(string) =>
new Promise((resolve, reject) => {
setTimeout(() => {
string += "bar";
resolve(string);
}, 1);
}),
)
// 2. receive "foobar", register a callback function to work on that string
// and print it to the console, but not before returning the unworked on
// string to the next then
.then((string) => {
setTimeout(() => {
string += "baz";
console.log(string); // foobarbaz
}, 1);
return string;
})
// 3. print helpful messages about how the code in this section will be run
// before the string is actually processed by the mocked asynchronous code in the
// previous then block.
.then((string) => {
console.log(
"Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising",
);
// Note that `string` will not have the 'baz' bit of it at this point. This
// is because we mocked that to happen asynchronously with a setTimeout function
console.log(string); // foobar
});
// Logs, in order:
// Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising
// foobar
// foobarbaz
Der von then() zurückgegebene Wert wird auf die gleiche Weise wie Promise.resolve() aufgelöst. Das bedeutet, dass thenable Objekte unterstützt werden, und wenn der Rückgabewert kein Promise ist, wird es implizit in ein Promise eingehüllt und dann aufgelöst.
const p2 = new Promise((resolve, reject) => {
resolve(1);
});
p2.then((value) => {
console.log(value); // 1
return value + 1;
}).then((value) => {
console.log(value, "- A synchronous value works"); // 2 - A synchronous value works
});
p2.then((value) => {
console.log(value); // 1
});
Ein then-Aufruf gibt ein Promise zurück, das schließlich abgelehnt wird, wenn die Funktion einen Fehler wirft oder ein abgelehntes Promise zurückgibt.
Promise.resolve()
.then(() => {
// Makes .then() return a rejected promise
throw new Error("Oh no!");
})
.then(
() => {
console.log("Not called.");
},
(error) => {
console.error(`onRejected function called: ${error.message}`);
},
);
In der Praxis ist es oft wünschenswert, abgelehnte Promises catch() anstelle der then()-Zwei-Fall-Syntax zu behandeln, wie unten demonstriert.
Promise.resolve()
.then(() => {
// Makes .then() return a rejected promise
throw new Error("Oh no!");
})
.catch((error) => {
console.error(`onRejected function called: ${error.message}`);
})
.then(() => {
console.log("I am always called even if the prior then's promise rejects");
});
In allen anderen Fällen wird das zurückgegebene Promise schließlich erfüllt. Im folgenden Beispiel gibt das erste then() 42 in einem erfüllten Promise zurück, obwohl das vorherige Promise in der Kette abgelehnt wurde.
Promise.reject(new Error("Oh no!"))
.then(
() => 99,
() => 42,
) // onRejected returns 42 which is wrapped in a fulfilled Promise
.then((solution) => console.log(`Resolved with ${solution}`)); // Fulfilled with 42
Wenn onFulfilled ein Promise zurückgibt, wird der Rückgabewert von then basierend auf dem endgültigen Status dieses Promises erfüllt/abgelehnt.
function resolveLater(resolve, reject) {
setTimeout(() => {
resolve(10);
}, 1000);
}
function rejectLater(resolve, reject) {
setTimeout(() => {
reject(new Error("Error"));
}, 1000);
}
const p1 = Promise.resolve("foo");
// Return promise here, that will be resolved to 10 after 1 second
const p2 = p1.then(() => new Promise(resolveLater));
p2.then(
(v) => {
console.log("resolved", v); // "resolved", 10
},
(e) => {
// not called
console.error("rejected", e);
},
);
// Return promise here, that will be rejected with 'Error' after 1 second
const p3 = p1.then(() => new Promise(rejectLater));
p3.then(
(v) => {
// not called
console.log("resolved", v);
},
(e) => {
console.error("rejected", e); // "rejected", 'Error'
},
);
Sie können Verkettung verwenden, um eine Funktion mit einer auf Promise basierenden API auf der Grundlage einer anderen solchen Funktion zu implementieren.
function fetchCurrentData() {
// The fetch() API returns a Promise. This function
// exposes a similar API, except the fulfillment
// value of this function's Promise has had more
// work done on it.
return fetch("current-data.json").then((response) => {
if (response.headers.get("content-type") !== "application/json") {
throw new TypeError();
}
const j = response.json();
// maybe do something with j
// fulfillment value given to user of
// fetchCurrentData().then()
return j;
});
}
Asynchronität von then()
Das folgende Beispiel demonstriert die Asynchronität der then-Methode.
// Using a resolved promise 'resolvedProm' for example,
// the function call 'resolvedProm.then(...)' returns a new promise immediately,
// but its handler '(value) => {...}' will get called asynchronously as demonstrated by the console.logs.
// the new promise is assigned to 'thenProm',
// and thenProm will be resolved with the value returned by handler
const resolvedProm = Promise.resolve(33);
console.log(resolvedProm);
const thenProm = resolvedProm.then((value) => {
console.log(
`this gets called after the end of the main stack. the value received is: ${value}, the value returned is: ${
value + 1
}`,
);
return value + 1;
});
console.log(thenProm);
// Using setTimeout, we can postpone the execution of a function to the moment the stack is empty
setTimeout(() => {
console.log(thenProm);
});
// Logs, in order:
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 33}
// Promise {[[PromiseStatus]]: "pending", [[PromiseResult]]: undefined}
// "this gets called after the end of the main stack. the value received is: 33, the value returned is: 34"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 34}
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> # sec-promise.prototype.then> |