Versprechen haben Status, sie beginnen als ausstehend und können sich mit folgenden Punkten zufrieden geben:
- erfüllt bedeutet, dass die Berechnung erfolgreich abgeschlossen wurde.
- abgelehnt, was bedeutet, dass die Berechnung fehlgeschlagen ist.
Versprechende Rückgabefunktionen sollten niemals ausgelöst werden , sondern stattdessen Ablehnungen zurückgeben. Wenn Sie eine Funktion zum Zurückgeben von Versprechungen deaktivieren, werden Sie gezwungen, sowohl a } catch {
als auch a zu verwenden .catch
. Menschen, die vielversprechende APIs verwenden, erwarten keine Versprechen. Wenn Sie sich nicht sicher sind, wie asynchrone APIs in JS funktionieren, lesen Sie zuerst diese Antwort .
1. DOM-Last oder ein anderes einmaliges Ereignis:
Das Erstellen von Versprechungen bedeutet also im Allgemeinen, anzugeben, wann sie sich niederlassen - das heißt, wann sie in die erfüllte oder abgelehnte Phase wechseln, um anzuzeigen, dass die Daten verfügbar sind (und mit denen zugegriffen werden kann .then
).
Mit modernen Versprechen-Implementierungen, die den Promise
Konstruktor wie native ES6-Versprechen unterstützen:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Sie würden dann das resultierende Versprechen wie folgt verwenden:
load().then(function() {
// Do things after onload
});
Mit Bibliotheken, die verzögert unterstützen (Verwenden wir hier $ q für dieses Beispiel, aber wir werden später auch jQuery verwenden):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Oder mit einer jQuery-ähnlichen API, die sich auf ein Ereignis einlässt, das einmal passiert:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Einfacher Rückruf:
Diese APIs sind ziemlich häufig, da Rückrufe in JS häufig vorkommen. Schauen wir uns den häufigen Fall von onSuccess
und an onFail
:
function getUserData(userId, onLoad, onFail) { …
Mit modernen Versprechen-Implementierungen, die den Promise
Konstruktor wie native ES6-Versprechen unterstützen:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
Mit Bibliotheken, die verzögert unterstützen (Verwenden wir hier für dieses Beispiel jQuery, aber wir haben oben auch $ q verwendet):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
jQuery bietet auch ein $.Deferred(fn)
Formular an, das den Vorteil hat, dass wir einen Ausdruck schreiben können, der das new Promise(fn)
Formular wie folgt sehr genau emuliert :
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Hinweis: Hier nutzen wir die Tatsache, dass die zurückgestellten resolve
und reject
Methoden einer jQuery "abnehmbar" sind. dh. Sie sind an die Instanz einer jQuery.Deferred () gebunden . Nicht alle Bibliotheken bieten diese Funktion an.
3. Rückruf im Knotenstil ("Nodeback"):
Rückrufe im Knotenstil (Nodebacks) haben ein bestimmtes Format, bei dem die Rückrufe immer das letzte Argument sind und der erste Parameter ein Fehler ist. Lassen Sie uns zunächst eine manuell versprechen:
getStuff("dataParam", function(err, data) { …
Zu:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
Mit Zurückgestellten können Sie Folgendes tun (verwenden wir Q für dieses Beispiel, obwohl Q jetzt die neue Syntax unterstützt, die Sie bevorzugen sollten ):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
Im Allgemeinen sollten Sie Dinge nicht zu viel manuell versprechen. Die meisten Versprechungsbibliotheken, die unter Berücksichtigung von Node entwickelt wurden, sowie native Versprechungen in Node 8+ verfügen über eine integrierte Methode zum Versprechen von Nodebacks. Zum Beispiel
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. Eine ganze Bibliothek mit Rückrufen im Knotenstil:
Hier gibt es keine goldene Regel, Sie versprechen sie eins nach dem anderen. Bei einigen Versprechen-Implementierungen können Sie dies jedoch in großen Mengen tun, z. B. in Bluebird. Das Konvertieren einer Nodeback-API in eine Versprechen-API ist so einfach wie:
Promise.promisifyAll(API);
Oder mit einheimischen Versprechungen in Node :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Anmerkungen:
- Wenn Sie sich in einem
.then
Handler befinden, müssen Sie natürlich keine Dinge versprechen. Wenn Sie ein Versprechen von einem .then
Handler zurückgeben, wird es mit dem Wert dieses Versprechens aufgelöst oder abgelehnt. Das Werfen von einem .then
Handler ist ebenfalls eine gute Praxis und lehnt das Versprechen ab - dies ist das berühmte Versprechen, Sicherheit zu werfen.
- In einem tatsächlichen
onload
Fall sollten Sie addEventListener
eher als verwenden onX
.