อัปเดต (2017)
ที่นี่ในปี 2017 Promises ถูกสร้างขึ้นใน JavaScript ซึ่งถูกเพิ่มโดยข้อกำหนด ES2015 (โพลีฟิลล์มีให้สำหรับสภาพแวดล้อมที่ล้าสมัยเช่น IE8-IE11) ไวยากรณ์ที่ใช้ใช้การเรียกกลับที่คุณส่งผ่านไปยังตัวPromise
สร้าง (ตัวPromise
ดำเนินการ ) ซึ่งรับฟังก์ชั่นสำหรับการแก้ไข / ปฏิเสธสัญญาเป็นอาร์กิวเมนต์
ประการแรกเนื่องจากasync
ตอนนี้มีความหมายใน JavaScript (แม้ว่าจะเป็นเพียงคำหลักในบางบริบท) ฉันจะใช้later
เป็นชื่อของฟังก์ชันเพื่อหลีกเลี่ยงความสับสน
ความล่าช้าขั้นพื้นฐาน
การใช้คำสัญญาดั้งเดิม (หรือโพลีฟิลล์ที่ซื่อสัตย์) จะมีลักษณะดังนี้:
function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
โปรดทราบว่าถือว่าเป็นเวอร์ชันsetTimeout
ที่สอดคล้องกับคำจำกัดความสำหรับเบราว์เซอร์ที่setTimeout
ไม่ส่งผ่านอาร์กิวเมนต์ใด ๆ ไปยังการเรียกกลับเว้นแต่คุณจะให้หลังจากช่วงเวลาดังกล่าว (ซึ่งอาจไม่เป็นจริงในสภาพแวดล้อมที่ไม่ใช่เบราว์เซอร์และไม่เคยเป็นมาก่อน จริงบน Firefox แต่ตอนนี้เป็นจริงบน Chrome และแม้กระทั่งใน IE8)
Basic Delay with Value
หากคุณต้องการให้ฟังก์ชันของคุณเป็นทางเลือกในการส่งผ่านค่าความละเอียดบนเบราว์เซอร์สมัยใหม่ที่คลุมเครือซึ่งช่วยให้คุณสามารถให้อาร์กิวเมนต์เพิ่มเติมsetTimeout
หลังจากการหน่วงเวลาแล้วส่งผ่านไปยังการเรียกกลับเมื่อถูกเรียกคุณสามารถทำได้ (Firefox และ Chrome ปัจจุบัน IE11 + น่าจะเป็น Edge ไม่ใช่ IE8 หรือ IE9 ไม่รู้เกี่ยวกับ IE10):
function later(delay, value) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, value);
});
}
หากคุณใช้ฟังก์ชัน ES2015 + ลูกศรสิ่งนี้จะกระชับมากขึ้น:
function later(delay, value) {
return new Promise(resolve => setTimeout(resolve, delay, value));
}
หรือแม้กระทั่ง
const later = (delay, value) =>
new Promise(resolve => setTimeout(resolve, delay, value));
ยกเลิกได้ล่าช้าด้วยค่า
หากคุณต้องการยกเลิกการหมดเวลาคุณไม่สามารถคืนสัญญาได้later
เนื่องจากไม่สามารถยกเลิกสัญญาได้
แต่เราสามารถส่งคืนวัตถุได้อย่างง่ายดายด้วยcancel
วิธีการและตัวเข้าถึงสำหรับคำสัญญาและปฏิเสธสัญญาเมื่อยกเลิก:
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 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);
คำตอบเดิมจากปี 2014
โดยปกติคุณจะมีคลังคำสัญญา (อันที่คุณเขียนเองหรือหนึ่งในห้องสมุดที่มีอยู่) โดยปกติไลบรารีนั้นจะมีออบเจ็กต์ที่คุณสามารถสร้างและ "แก้ไข" ในภายหลังและอ็อบเจ็กต์นั้นจะมี "สัญญา" ที่คุณจะได้รับ
จากนั้นlater
จะมีลักษณะดังนี้:
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise();
}
ในความคิดเห็นเกี่ยวกับคำถามฉันถามว่า:
คุณกำลังพยายามสร้างห้องสมุดสัญญาของคุณเองหรือไม่?
และคุณพูด
ฉันไม่ได้ แต่ฉันเดาว่าตอนนี้นั่นคือสิ่งที่ฉันพยายามเข้าใจจริงๆ ว่าห้องสมุดจะทำอย่างไร
เพื่อช่วยในการทำความเข้าใจต่อไปนี้เป็นตัวอย่างพื้นฐานที่ไม่สอดคล้องกับ Promises-A จากระยะไกล: Live Copy
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Very basic promises</title>
</head>
<body>
<script>
(function() {
var PromiseThingy = (function() {
function triggerCallback(callback, promise) {
try {
callback(promise.resolvedValue);
}
catch (e) {
}
}
function Promise() {
this.callbacks = [];
}
Promise.prototype.then = function(callback) {
var thispromise = this;
if (!this.resolved) {
this.callbacks.push(callback);
}
else {
setTimeout(function() {
triggerCallback(callback, thispromise);
}, 0);
}
return this;
};
function PromiseThingy() {
this.p = new 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);
}
}
};
PromiseThingy.prototype.promise = function() {
return this.p;
};
return PromiseThingy;
})();
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise();
}
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>