Vert.x
乃神器也,管玩管住還包飯,異步處理,很多人頭疼的callback hell
(回調(diào)地獄),也就是金字塔,不知不覺(jué)就走入了金字塔的陷阱里,一般callback
都發(fā)生在異步處理期間,而異步處理,除了少數(shù)數(shù)據(jù)量極大的cpu intense
的代碼塊以外(這部分主要通過(guò)降低算法時(shí)間復(fù)雜度來(lái)優(yōu)化),絕大多數(shù)都集中在io
上,將一個(gè)io
操作包裝成一個(gè)異步程序塊來(lái)執(zhí)行,是比較常見(jiàn)的優(yōu)化方式,vert.x
的io
集中在以下幾個(gè)部分。
第一,eventbus.send()方法。
第二,jdbcclient.getconnection
以及connection.update/query
等方法。
第三,httpclient.get/post等方法,其中前兩個(gè)都可以通過(guò)vert.x自帶的Future來(lái)對(duì)付。
首先我們要實(shí)例化一個(gè)future
對(duì)象:
Future<MyResult> future = Future.future();
然后future
有幾個(gè)方法值得注意,其中一個(gè)是setHandler
方法,這個(gè)方法就是設(shè)置后續(xù)處理的函數(shù),另外一個(gè),與之相對(duì)應(yīng)的是completer()
方法,這個(gè)方法返回的就是setHandler
方法set
的handler
函數(shù),通俗點(diǎn)說(shuō),就是getHandler()
方法,在callback
位置調(diào)用該方法,就可以在callback
的時(shí)候執(zhí)行handler
方法/函數(shù),比如原本是:
vertx.eventBus().send(CommerceVerticle.class.getName(),myAsyncResult -> {...});
經(jīng)過(guò)改寫(xiě)之后,就變成了:
vertx.eventBus().send(CommerceVerticle.class.getName(),future.completer());
future.setHandler(myAsyncResult -> {...});
這樣通過(guò)拆分原來(lái)的內(nèi)嵌lambda
/匿名函數(shù)來(lái)達(dá)到扁平化的效果。
callback hell
一個(gè)典型特征就是金字塔,也就是經(jīng)過(guò)多層回調(diào)/callback
函數(shù)嵌套之后,程序會(huì)變成:
ar -> {
ar1 -> {
ar2 -> {
...
}
}
};
這種方式,或者fp
里面常見(jiàn)的(+ 1 (+ 1 (+ 1 1)))
;如果強(qiáng)行format
的話,就會(huì)變成一個(gè)多層多次縮進(jìn)的,向右凸起的金字塔,極為丑陋,但是如果不這么做,又無(wú)法保證順序,所以為了保證順序的同時(shí),我們要扁平化該金字塔,那么如何保證順序呢?
用compose
方法,比如:
Future fut1 = Future.future();
Future fut2 = Future.future();
fut1.compose(asyncMyResult -> {
...
fut2.complete();
...
}, fut2);
fut2.setHandler(asyncMyResult2 -> {
...
});
那么當(dāng)fut1
被觸發(fā)之后,如果成功,則執(zhí)行compose
方法里面的第一個(gè)參數(shù),也就是那個(gè)回調(diào)函數(shù)/handler
,如果失敗,則直接傳遞給compose
方法的第二個(gè)參數(shù),也就是fut2
,依次類(lèi)推,便可以很輕松地組裝出你想要的扁平化鏈條,使得多層縮進(jìn)的噩夢(mèng)不再。
利用這種方式,可以扁平化處理vertx.eventBus()
,jdbcClient.getConnection()
等包含有異步callback
的代碼塊。
至于Vert.x
自帶的httpclient
,這個(gè)稍微有些特殊,因?yàn)閳?zhí)行get/post
等方法的時(shí)候,response handler
并不能囊括全部情況,尤其是常見(jiàn)的超時(shí)/timeout
,屬于exception
范疇,也就是說(shuō),要想囊括全部返回情況,至少需要response
的body handler
,同時(shí)也需要一個(gè)exception handler
,最后還要調(diào)用end方法才能將全部常見(jiàn)的情況全部覆蓋住,代碼如下:
client1.get(port, ip, url, response -> {
response.bodyHandler(respBody -> {
//這里處理正常返回
});
}).exceptionHandler(exception -> {
//這里處理超時(shí)
}).end();
如果要在這里面用future
的話,需要顯式處理標(biāo)識(shí)成功future.complete(...)
或者失敗future.fail(...)
另外,常見(jiàn)的httpClient.getNow()
;等方法相當(dāng)于:
client1.get(port, ip, url, response -> {
response.bodyHandler(respBody -> {
//這里處理正常返回
});
}).end();
也就是沒(méi)有exception handler
的普通get/post
等方法+end
方法,所以如果用getNow
等方法發(fā)送請(qǐng)求,會(huì)無(wú)法捕捉處理timeout
超時(shí)異常。
通過(guò)這篇文章想必對(duì)Vertx如何避免callback hell有所了解。
全科龍婷▼升職加薪