Update (2017)
Hier sind 2017 Versprechen in JavaScript integriert, sie wurden durch die ES2015-Spezifikation hinzugefügt (Polyfills sind für veraltete Umgebungen wie IE8-IE11 verfügbar). Die Syntax verwendet einen Rückruf, den Sie an den Promise
Konstruktor (den Promise
Executor ) übergeben, der die Funktionen zum Auflösen / Ablehnen des Versprechens als Argumente erhält.
Erstens, da es async
jetzt eine Bedeutung in JavaScript hat (obwohl es in bestimmten Kontexten nur ein Schlüsselwort ist), werde ich es later
als Namen der Funktion verwenden, um Verwirrung zu vermeiden.
Grundverzögerung
Mit einheimischen Versprechungen (oder einer originalgetreuen Polyfüllung) würde es so aussehen:
function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
Beachten Sie, dass das setzt voraus , eine Version , setTimeout
das ist kompatibel mit der Definition für Browser , wo setTimeout
keine Argumente an die Callback übergeben wird , wenn man sich nach der Pause geben (dies ist nicht in Nicht-Browser - Umgebungen wahr sein kann, und nicht genutzt werden wahr auf Firefox, aber jetzt; es ist wahr auf Chrome und sogar zurück auf IE8).
Grundverzögerung mit Wert
Wenn Sie möchten, dass Ihre Funktion optional einen Auflösungswert in einem vage modernen Browser setTimeout
übergibt, in dem Sie nach der Verzögerung zusätzliche Argumente angeben und diese beim Aufruf an den Rückruf übergeben können, können Sie dies tun (aktuelles Firefox und Chrome; IE11 +) , vermutlich Edge; nicht IE8 oder IE9, keine Ahnung von IE10):
function later(delay, value) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, value); // Note the order, `delay` before `value`
/* Or for outdated browsers that don't support doing that:
setTimeout(function() {
resolve(value);
}, delay);
Or alternately:
setTimeout(resolve.bind(null, value), delay);
*/
});
}
Wenn Sie die Pfeilfunktionen ES2015 + verwenden, kann dies präziser sein:
function later(delay, value) {
return new Promise(resolve => setTimeout(resolve, delay, value));
}
oder auch
const later = (delay, value) =>
new Promise(resolve => setTimeout(resolve, delay, value));
Stornierbare Verzögerung mit Wert
Wenn Sie das Timeout stornieren möchten, können Sie nicht einfach ein Versprechen von zurückgeben later
, da Versprechen nicht storniert werden können.
Wir können jedoch problemlos ein Objekt mit einer cancel
Methode und einem Accessor für das Versprechen zurückgeben und das Versprechen beim Abbrechen ablehnen:
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
Live-Beispiel:
const later = (delay, value) => {
let timer = 0;
let reject = null;
const promise = new Promise((resolve, _reject) => {
reject = _reject;
timer = setTimeout(resolve, delay, value);
});
return {
get promise() { return promise; },
cancel() {
if (timer) {
clearTimeout(timer);
timer = 0;
reject();
reject = null;
}
}
};
};
const l1 = later(100, "l1");
l1.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l1 cancelled"); });
const l2 = later(200, "l2");
l2.promise
.then(msg => { console.log(msg); })
.catch(() => { console.log("l2 cancelled"); });
setTimeout(() => {
l2.cancel();
}, 150);
Ursprüngliche Antwort von 2014
Normalerweise haben Sie eine Versprechensbibliothek (eine, die Sie selbst schreiben, oder eine der mehreren da draußen). Diese Bibliothek hat normalerweise ein Objekt, das Sie erstellen und später "auflösen" können, und dieses Objekt hat ein "Versprechen", das Sie von ihm erhalten können.
Dann later
würde es ungefähr so aussehen:
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise(); // Note we're not returning `p` directly
}
In einem Kommentar zu der Frage fragte ich:
Versuchen Sie, Ihre eigene Versprechensbibliothek zu erstellen?
und du sagtest
Ich war es nicht, aber ich denke jetzt ist es tatsächlich das, was ich zu verstehen versuchte. So würde es eine Bibliothek machen
Um dieses Verständnis zu erleichtern, finden Sie hier ein sehr einfaches Beispiel, das nicht im entferntesten Promises-A-konform ist: Live Copy
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Very basic promises</title>
</head>
<body>
<script>
(function() {
// ==== Very basic promise implementation, not remotely Promises-A compliant, just a very basic example
var PromiseThingy = (function() {
// Internal - trigger a callback
function triggerCallback(callback, promise) {
try {
callback(promise.resolvedValue);
}
catch (e) {
}
}
// The internal promise constructor, we don't share this
function Promise() {
this.callbacks = [];
}
// Register a 'then' callback
Promise.prototype.then = function(callback) {
var thispromise = this;
if (!this.resolved) {
// Not resolved yet, remember the callback
this.callbacks.push(callback);
}
else {
// Resolved; trigger callback right away, but always async
setTimeout(function() {
triggerCallback(callback, thispromise);
}, 0);
}
return this;
};
// Our public constructor for PromiseThingys
function PromiseThingy() {
this.p = new Promise();
}
// Resolve our underlying promise
PromiseThingy.prototype.resolve = function(value) {
var n;
if (!this.p.resolved) {
this.p.resolved = true;
this.p.resolvedValue = value;
for (n = 0; n < this.p.callbacks.length; ++n) {
triggerCallback(this.p.callbacks[n], this.p);
}
}
};
// Get our underlying promise
PromiseThingy.prototype.promise = function() {
return this.p;
};
// Export public
return PromiseThingy;
})();
// ==== Using it
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise(); // Note we're not returning `p` directly
}
display("Start " + Date.now());
later().then(function() {
display("Done1 " + Date.now());
}).then(function() {
display("Done2 " + Date.now());
});
function display(msg) {
var p = document.createElement('p');
p.innerHTML = String(msg);
document.body.appendChild(p);
}
})();
</script>
</body>
</html>