Vert.x
乃神器也,管玩管住还包饭,异步处理,很多人头疼的callback hell
(回调地狱),也就是金字塔,不知不觉就走入了金字塔的陷阱里,一般callback
都发生在异步处理期间,而异步处理,除了少数数据量极大的cpu intense
的代码块以外(这部分主要通过降低算法时间复杂度来优化),绝大多数都集中在io
上,将一个io
操作包装成一个异步程序块来执行,是比较常见的优化方式,vert.x
的io
集中在以下几个部分。
第一,eventbus.send()方法。
第二,jdbcclient.getconnection
以及connection.update/query
等方法。
第三,httpclient.get/post等方法,其中前两个都可以通过vert.x自带的Future来对付。
首先我们要实例化一个future
对象:
Future future = Future.future();
然后future
有几个方法值得注意,其中一个是setHandler
方法,这个方法就是设置后续处理的函数,另外一个,与之相对应的是completer()
方法,这个方法返回的就是setHandler
方法set
的handler
函数,通俗点说,就是getHandler()
方法,在callback
位置调用该方法,就可以在callback
的时候执行handler
方法/函数,比如原本是:
vertx.eventBus().send(CommerceVerticle.class.getName(),myAsyncResult -> {...});
经过改写之后,就变成了:
vertx.eventBus().send(CommerceVerticle.class.getName(),future.completer());
future.setHandler(myAsyncResult -> {...});
这样通过拆分原来的内嵌lambda
/匿名函数来达到扁平化的效果。
callback hell
一个典型特征就是金字塔,也就是经过多层回调/callback
函数嵌套之后,程序会变成:
ar -> {
ar1 -> {
ar2 -> {
...
}
}
};
这种方式,或者fp
里面常见的(+ 1 (+ 1 (+ 1 1)))
;如果强行format
的话,就会变成一个多层多次缩进的,向右凸起的金字塔,极为丑陋,但是如果不这么做,又无法保证顺序,所以为了保证顺序的同时,我们要扁平化该金字塔,那么如何保证顺序呢?
用compose
方法,比如:
Future fut1 = Future.future();
Future fut2 = Future.future();
fut1.compose(asyncMyResult -> {
...
fut2.complete();
...
}, fut2);
fut2.setHandler(asyncMyResult2 -> {
...
});
那么当fut1
被触发之后,如果成功,则执行compose
方法里面的第一个参数,也就是那个回调函数/handler
,如果失败,则直接传递给compose
方法的第二个参数,也就是fut2
,依次类推,便可以很轻松地组装出你想要的扁平化链条,使得多层缩进的噩梦不再。
利用这种方式,可以扁平化处理vertx.eventBus()
,jdbcClient.getConnection()
等包含有异步callback
的代码块。
至于Vert.x
自带的httpclient
,这个稍微有些特殊,因为执行get/post
等方法的时候,response handler
并不能囊括全部情况,尤其是常见的超时/timeout
,属于exception
范畴,也就是说,要想囊括全部返回情况,至少需要response
的body handler
,同时也需要一个exception handler
,最后还要调用end方法才能将全部常见的情况全部覆盖住,代码如下:
client1.get(port, ip, url, response -> {
response.bodyHandler(respBody -> {
//这里处理正常返回
});
}).exceptionHandler(exception -> {
//这里处理超时
}).end();
如果要在这里面用future
的话,需要显式处理标识成功future.complete(...)
或者失败future.fail(...)
另外,常见的httpClient.getNow()
;等方法相当于:
client1.get(port, ip, url, response -> {
response.bodyHandler(respBody -> {
//这里处理正常返回
});
}).end();
也就是没有exception handler
的普通get/post
等方法+end
方法,所以如果用getNow
等方法发送请求,会无法捕捉处理timeout
超时异常。
通过这篇文章想必对Vertx如何避免callback hell有所了解。
全科龙婷▼升职加薪