array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 通过netty解析future - 爱码网

 netty中的future继承自jdk中cocurrent包下future的接口。

通过netty解析future

通过netty解析future

Future的V可以是void,不一定是有返回值的,所以通过返回值来判断task isDone()是错误的。所以isDone的判断不应该通过返回值来做。只有isDone了之后,才去做get操作。所以get里面也会抛异常。

通过isDone来判断是否结束了。

通过netty解析future

正常的Future在jdk中的使用方法,Future针对的就是一个task,task往往是一个runnable,Future和runnable在一起,他就是一个task。

FutureTask<String> future=new FutureTask<>(task);

executor.execute(future);

把future放在execute里面,执行的是runnable对象,只不过是用Future管理了一下。Task里面需要设定状态,Future是针对要执行的任务的封装,对任务做了一个增强的操作。但是netty里面的future,这些方法是不够的。所以添加了一些接口,而且是异步的操作。

通过netty解析future

jdk里面的Future是isDone,没有判断是否成功,只判断了是否取消了(isCalled),netty里面的future是isSuccess,还加了是否可以取消。是对状态判断的补充。cause方法,抛出异常之后可以知道是怎样跑出的什么异常。netty的future,很核心的一个方法:addListener,通过isDone判断这个future结束了,结束了之后立马唤醒这个listener。相当于就是一个回调。

通过netty解析future

有增加一般就有删除,所以有removeListener。

future需要特别注意的方法有三个,isDone,isSuccess,addListener。

知道这个之后,再来说一下函数式编程,函数式编程会强调一个promise。就是成功之后会做什么事,失败之后会做什么事。promise和响应式编程很像,有onNext,onComplete,onError这几种处理,你有元素下发的时候怎么处理,当你正常结束的时候怎么处理,当出错的时候怎么处理。我们的正常使用只是一个地址的访问,给我返回结果,我们只需要对结果进行判断它是成功还是失败。如果只需要考虑这2种,使用promise就可以了。所以future又拓展了一个promise。

通过netty解析future

如何判断是isSuccess,promise提供了setSuccess,trySuccess,标记为success同时通知所有的listener。

通过netty解析future

promise接口继承自future,所以它重写了一些方法,把返回值有Future改为了Promise。以addListener为例,在函数式编程中,添加的是一个动作,操作的是Future,很明显是一个函数式接口,就是结束之后应该做什么,只不过标记了是EventListener。EventListener是一个标记,并没有设定方法。

通过netty解析future

通过netty解析future

通过netty解析future

在netty中是如何使用的,我们更多的是针对channel,可以以channel为例,来分析promise一些比较核心的用法。

首先有个接口,ChannelPromise,同样ChannelPromise返回的都是ChannelPromise,它继承ChannelFuture和Promise。

通过netty解析future

然后来看一下ChannelFuture的默认使用:DefaultChannelFuture

通过netty解析future

他继承自DefaultPromise,先看一下DefaultPromise:

通过netty解析future

先看addListener方法,addListener是一个动作,它需要做一些事情。

通过netty解析future

一个是添加进去,addListener0,添加进去肯定是要做管理的,那如何管理,要么是容器要么是链表。

通过netty解析future

通过netty解析future

那这个里面,DefaultFutureListener里面是一个容器,一个数组,只不过是限定了类型。

addListener做了2件事,一个是做添加,添加完之后,就要做判断这个task是否已经结束了。jdk中的Future的一个核心方法之一就是isDone().人物的结束与否并不是看你是否返回了结果,而是看isDone,所以在做任何事之前,先判断是否isDone。假如结束之后就notifyListeners(),之所以说addListener它是一个回调,是因为notifyListeners可以拿到一个executer,然后做事情。

通过netty解析future

通过netty解析future

通过netty解析future

对listener进行遍历,然后执行。我们管理了一个针对Future的动作。

监听器就是一个回调,只不过做了相应的封装。

所以在添加listener的时候,一定要注意有一个isDone的判断。

看一下DefaultPromise的isDone():

通过netty解析future

假如我们并没有设置值的话,result就是null,他只不过传入了一个Object。它并没有限定类型,可以放DefaultPromise的V类型,同样也可以只是一个Object,管理几种装态,这个isDone只是代表结束了,并不是代表成功了。

通过netty解析future

通过netty解析future

isDone之后,需要做isSuccess的判断。那isSuccess应该放在哪一块去做呢?

还是看DefaultPromise:

通过netty解析future

默认情况下它是成功或者有值的。

然后来看一下DefaultChannelFuture的setSuccess方法:

通过netty解析future

setSuccess为null,然后trySuccess也是null。

通过netty解析future

通过netty解析future

如果你传的是null,就设置为SUCCESS.设置完之后就是一个通知的回调。

然后看一下他们常见的调用:

通过netty解析future

通过netty解析future

通过netty解析future

设置为success状态之后返回,在使用的时候只需要点addListener即可,就直接去执行listener中的动作了。

通过netty解析future

pool.acquire()已经把success设置进去了,所以只需要addListener即可。他的isDone就结束了。所以addLIstener就直接去执行相关的代码了。

通过netty解析future

同样的,获取连接也是先去判断是否isDone,结束了的话,就做结束之后的动作,

通过netty解析future

首先我自己定义了一个promise,你拿到这个channel,放到这个promise里面,外层的话,就可以做到一个控制。在这一块儿,直接加一个listener就行了。用的就是netty的一贯的套路。

在使用future的使用,通过这种方式,我们学会使用addListener,我们要指导addListener要经过哪些操作,第一步添加,第二步,通过isDone判断是否结束了,结束了的话,就做一些事,isDone后面紧跟的就是isSuccess,我是不是成功设定了,成功了的话,我才会去取。假如失败的话,就tryFuture,如果有异常的话,就future.cause().

接着我们在看一下其他的代码,

通过netty解析future

config().group().register(channel)得到一个ChannelFuture,如果要判断isDone,再判断isSuccess,不如直接判断cause()是否为null,不为null,再判断是否注册了,没有注册成功的话,就close,没有异常直接返回去,不会做任何其他的动作。

学过nio的就应该知道,注册其实还是要通过channel.register()来实现。

通过netty解析future

它通过ChannelPromise把Channel包裹进来,然后它就可以拿到当前的selector,

通过netty解析future

所以可以把promise看成一个针对channel的动作。

转载于:https://my.oschina.net/u/3944601/blog/3074084

相关文章: