Обіцянка та майбутнє - це взаємодоповнюючі поняття. Майбутнє - це значення, яке буде отримано, колись у майбутньому, і ви можете робити з ним речі, коли ця подія станеться. Отже, це кінцева точка обчислення чи зчитування - це те, з чого ви отримуєте значення.
Обіцянка - це, за аналогією, письмова сторона обчислення. Ви створюєте обіцянку, в якій ви будете розміщувати результат обчислення, і з цієї обіцянки ви отримаєте майбутнє, яке буде використано для зчитування результату, який було вкладено в обіцянку. Коли ви виконаєте обіцянку, або через невдачу, або через успіх, ви ініціюєте всю поведінку, яка була прив’язана до пов'язаного майбутнього.
Щодо вашого першого питання, то як може бути, що для обіцянки р ми маємо p.future == p
. Ви можете уявити це як буфер з одним елементом - контейнер, який спочатку порожній, і ви можете зберегти післямови одне значення, яке назавжди стане його вмістом. Тепер, залежно від вашої точки зору, це і обіцянка, і майбутнє. Це обіцяно для тих, хто має намір записати значення в буфер. Це майбутнє для того, хто чекає, коли це значення буде введено в буфер.
Зокрема, для одночасного API Scala, якщо ви подивитесь на ознаку Promise тут, ви побачите, як реалізовані методи із об’єкта-супутника Promise:
object Promise {
/** Creates a promise object which can be completed with a value.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
/** Creates an already completed Promise with the specified exception.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
/** Creates an already completed Promise with the specified result.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
Тепер ці реалізації обіцянок, DefaultPromise та KeptPromise можна знайти тут . Вони обидва розширюють базову маленьку рису, яка буває однаковою назвою, але вона знаходиться в іншому пакеті:
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
Тож ви можете зрозуміти, що вони мають на увазі p.future == p
.
DefaultPromise
є буфером, про який я мав на увазі вище, тоді як KeptPromise
є буфером із значенням, введеним з самого його створення.
Що стосується вашого прикладу, майбутній блок, який ви там використовуєте, насправді створює обіцянку за кадром. Давайте подивимося на визначення future
в тут :
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
Дотримуючись ланцюжка методів, ви потрапляєте в 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
}
}
Отже, як бачите, результат, який ви отримуєте від вашого продуцентського блоку, вливається в обіцянку.
ПІЗНІШЕ РЕДАКТУВАННЯ :
Щодо реального використання: Здебільшого ви не будете безпосередньо мати справу з обіцянками. Якщо ви будете використовувати бібліотеку, яка виконує асинхронні обчислення, тоді ви просто будете працювати з ф'ючерсами, повернутими методами бібліотеки. У цьому випадку обіцянки створює бібліотека - ви просто працюєте з кінцем читання того, що роблять ці методи.
Але якщо вам потрібно реалізувати власний асинхронний API, вам доведеться почати працювати з ними. Припустимо, вам потрібно реалізувати асинхронний HTTP-клієнт поверх, скажімо, Netty. Тоді ваш код буде виглядати приблизно так
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}