Pembaruan (2017)
Di sini, di tahun 2017, Promises dibuat ke dalam JavaScript, dan ditambahkan oleh spesifikasi ES2015 (polyfill tersedia untuk lingkungan lama seperti IE8-IE11). Sintaks yang mereka gunakan menggunakan callback yang Anda berikan ke Promise
konstruktor ( Promise
pelaksana ) yang menerima fungsi untuk menyelesaikan / menolak janji sebagai argumen.
Pertama, karena async
sekarang memiliki arti dalam JavaScript (meskipun itu hanya kata kunci dalam konteks tertentu), saya akan menggunakan later
nama fungsinya untuk menghindari kebingungan.
Penundaan Dasar
Menggunakan janji asli (atau polyfill yang setia) akan terlihat seperti ini:
function later(delay) {
return new Promise(function(resolve) {
setTimeout(resolve, delay);
});
}
Perhatikan bahwa itu mengasumsikan versi setTimeout
yang sesuai dengan definisi untuk browser di mana setTimeout
tidak meneruskan argumen apa pun ke callback kecuali Anda memberikannya setelah interval (ini mungkin tidak benar di lingkungan non-browser, dan tidak dulu benar di Firefox, tetapi sekarang; itu benar di Chrome dan bahkan di IE8).
Penundaan Dasar dengan Nilai
Jika Anda ingin fungsi Anda meneruskan nilai resolusi secara opsional, pada browser modern apa pun yang memungkinkan Anda memberikan argumen tambahan setTimeout
setelah penundaan dan kemudian meneruskannya ke callback saat dipanggil, Anda dapat melakukan ini (Firefox dan Chrome saat ini; IE11 + , mungkin Edge; bukan IE8 atau IE9, tidak tahu tentang IE10):
function later(delay, value) {
return new Promise(function(resolve) {
setTimeout(resolve, delay, value);
});
}
Jika Anda menggunakan fungsi panah ES2015 +, itu bisa lebih ringkas:
function later(delay, value) {
return new Promise(resolve => setTimeout(resolve, delay, value));
}
atau bahkan
const later = (delay, value) =>
new Promise(resolve => setTimeout(resolve, delay, value));
Penundaan yang Dapat Dibatalkan dengan Nilai
Jika Anda ingin memungkinkan untuk membatalkan waktu tunggu, Anda tidak bisa hanya mengembalikan janji dari later
, karena janji tidak bisa dibatalkan.
Tapi kita bisa dengan mudah mengembalikan objek dengan cancel
metode dan aksesor untuk promise, dan menolak promise saat pembatalan:
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;
}
}
};
};
Contoh Langsung:
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);
Jawaban Asli dari 2014
Biasanya Anda akan memiliki perpustakaan promise (yang Anda tulis sendiri, atau salah satu dari beberapa di luar sana). Perpustakaan itu biasanya akan memiliki objek yang bisa Anda buat dan kemudian "diselesaikan", dan objek itu akan memiliki "janji" yang bisa Anda dapatkan darinya.
Maka later
akan cenderung terlihat seperti ini:
function later() {
var p = new PromiseThingy();
setTimeout(function() {
p.resolve();
}, 2000);
return p.promise();
}
Dalam komentar atas pertanyaan itu, saya bertanya:
Apakah Anda mencoba membuat pustaka janji Anda sendiri?
dan kamu berkata
Saya tidak, tetapi saya rasa sekarang itulah yang sebenarnya saya coba pahami. Begitulah cara perpustakaan melakukannya
Untuk membantu pemahaman itu, berikut adalah contoh yang sangat mendasar , yang tidak sesuai dengan Promises-A dari jarak jauh: 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>