A word on Vert.x promise / future objects and callbacks
Vert.x futures are not JDK futures: they can be composed and queried in a non-blocking fashion. They shall be used for simple coordination of asynchronous tasks, and especially those of deploying verticles and checking if they were successfully deployed or not.
The Vert.x core APIs are based on callbacks to notify of asynchronous events. The seasoned developer will naturally think that this opens the door to the so-called “callback hell” where multiple levels of nested callbacks render the code difficult to comprehend as illustrated by this fictional code:
foo.a(1, res1 -> {
if (res1.succeeded()) {
bar.b("abc", 1, res2 -> {
if (res.succeeded()) {
baz.c(res3 -> {
dosomething(res1, res2, res3, res4 -> {
// (...)
});
});
}
});
}
});
While the core APIs could have been designed to favor promises and futures, the choice of callbacks as the cardinal model is actually interesting since it allows different programming abstractions to be used. Vert.x is a largely un-opinionated project, and callbacks allow the implementation of different models that better cope with asynchronous programming: reactive extensions (via RxJava), promises and futures, fibers (using bytecode instrumentation), etc.
Since all Vert.x APIs are callback-oriented before other abstractions like RxJava can be leveraged, this guide only uses callbacks in the first sections to ensure that the reader gets familiar with the core concepts in Vert.x. It is also arguably easier to start with callbacks to draw a line between the many sections of asynchronous code. Once it becomes evident in the sample code that callbacks do not always lead to easily readable code, we will introduce the RxJava support to show how the same asynchronous code can be better expressed by thinking in streams of processed events.