Janji dan Masa Depan adalah konsep yang saling melengkapi. Masa Depan adalah nilai yang akan diambil, yah, suatu saat nanti dan Anda dapat melakukan banyak hal dengannya saat peristiwa itu terjadi. Oleh karena itu, ini adalah titik akhir pembacaan atau keluar dari sebuah komputasi - itu adalah sesuatu yang Anda ambil nilainya.
A Promise, dengan analogi, adalah sisi penulisan dari perhitungan. Anda membuat promise yang merupakan tempat Anda akan meletakkan hasil penghitungan dan dari promise tersebut Anda mendapatkan masa depan yang akan digunakan untuk membaca hasil yang dimasukkan ke dalam promise. Saat Anda akan menyelesaikan sebuah Janji, baik karena gagal atau berhasil, Anda akan memicu semua perilaku yang terkait dengan Masa Depan terkait.
Mengenai pertanyaan pertama Anda, bagaimana mungkin itu untuk janji yang kita miliki p.future == p
. Anda dapat membayangkan ini seperti buffer satu item - sebuah wadah yang awalnya kosong dan Anda dapat menyimpan satu nilai yang akan menjadi isinya selamanya. Sekarang, tergantung pada sudut pandang Anda, ini adalah Janji dan Masa Depan. Ini adalah janji untuk seseorang yang berniat untuk menulis nilai di buffer. Ini adalah masa depan bagi seseorang yang menunggu nilai itu dimasukkan ke dalam buffer.
Khususnya, untuk Scala concurrent API, jika Anda melihat sifat Promise di sini, Anda dapat melihat bagaimana metode dari objek pendamping Promise diimplementasikan:
object Promise {
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Sekarang, implementasi dari promise, DefaultPromise dan KeptPromise dapat ditemukan di sini . Keduanya memperluas sifat kecil dasar yang kebetulan memiliki nama yang sama, tetapi terletak di paket yang berbeda:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Jadi Anda bisa melihat apa yang mereka maksud p.future == p
.
DefaultPromise
adalah buffer yang saya maksud di atas, sedangkan KeptPromise
buffer dengan nilai yang dimasukkan dari pembuatannya.
Mengenai contoh Anda, blok masa depan yang Anda gunakan di sana sebenarnya menciptakan janji di balik layar. Mari kita lihat definisi future
di sini :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Dengan mengikuti rantai metode Anda berakhir di impl.Future :
private[concurrent] object Future {
class PromiseCompletingRunnable[T](body: => T) extends Runnable {
val promise = new Promise.DefaultPromise[T]()
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
val runnable = new PromiseCompletingRunnable(body)
executor.execute(runnable)
runnable.promise.future
}
}
Jadi, seperti yang Anda lihat, hasil yang Anda peroleh dari blok produser Anda dituangkan menjadi sebuah janji.
EDIT TERAKHIR :
Mengenai penggunaan dunia nyata: Seringkali Anda tidak akan berurusan dengan janji secara langsung. Jika Anda akan menggunakan pustaka yang melakukan komputasi asinkron, Anda hanya akan bekerja dengan masa depan yang dikembalikan oleh metode pustaka. Janji, dalam hal ini, dibuat oleh perpustakaan - Anda hanya bekerja dengan akhir membaca dari apa yang dilakukan metode tersebut.
Tetapi jika Anda perlu menerapkan API asinkron Anda sendiri, Anda harus mulai bekerja dengannya. Misalkan Anda perlu menerapkan klien HTTP asinkron di atas, katakanlah, Netty. Kemudian kode Anda akan terlihat seperti ini
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}