Rxjs入门实践——各种排序算法排序过程的可视化展示这几天学习了《算法》的排序篇。详见排序总结。想做点什么,可以通过Rxjs把各种排序算法的排序过程直观展示出来,只是为了练习Rxjs的使用本文不会过多介绍Rxjs的基本概念,重点介绍如何使用响应式编程的思想来实现功能。用于选择不同排序算法的数字按钮和下拉列表以及echart渲染的容器元素。点击按钮会随机生成300个随机数,页面会渲染出300个数字的直方图。选择排序算法后,页面开始显示排序过程。如果我们在排序过程中切换到另一种排序算法,则当前算法的可视化显示将停止,新排序算法的可视化显示将开始。思路是在排序过程中展示数组中的排序算法对于数据变化,我们需要在排序过程中周期性保存当前数组的快照,然后通过echart展示当前数组的数据。重复这个过程直到排序完成,我们将有一个代表排序过程的动画显示。具体实现在Rxjs中,一切皆有流。要实现这个功能,重要的是确定数据的流向,以及数据流向以后的变化过程。根据页面,可以明确判断出几条数据流向。点击按钮产生的数据流constcreateNumber$=Rx.Observable.fromEvent(query('.numberCreator'),'click')切换下拉列表产生的数据流constselect$=Rx.Observable.fromEvent(query('.sortTypes'),'change')点击按钮生成随机数组,渲染出echart图表。很明显,用到了map和do这两个操作符。createNumber$.map(e=>{returnnumberCreator()}).do(nums=>{constoption=getOption(nums)echartInstance.setOption(option)})在切换下拉列表的时候,我们需要得到一个当前选择的排序算法的标识符letcurrentTypeselect$.map(e=>e.target).map(x=>x.options[x.selectedIndex].value).map(type=>{return{type,timer:1}}).do(x=>{currentType=x.type})下面是关键点只点击按钮或切换下拉页面不应显示排序过程。排序过程的动画只有当两个事件流都被触发,其中一个事件流稍后再次触发时才会渲染,所以我们需要combineLatest算子将两个Combine两个数据流合并为一个constcombine$=Rx.Observable.combineLatest(createNumber$,select$)现在在combine$数据流中我们有一个随机数组和排序类型[Array[300],'1']然后排序算法应该就可以了,这里想想[]如何生成我们排序算法排序过程中的数据快照?[]生成的数据快照什么时候会被echart渲染出来?对于第一点,我们需要将排序算法封装成一个自定义的算子,在排序过程中不断的进行next()数据快照。至此,我们的数据流就变成了未来一段时间内可以不断产生新的Values。数据流Rx.Observable.prototype.sort=function(){constinput=thisreturnRx.Observable.create((observer)=>{input.subscribe((arr)=>{constnums=clone(arr[0])constselect=arr[1]constsortMethod=sortTypes[select.type]sortMethod(nums,function(arr){observer.next({nums:JSON.parse(JSON.stringify(arr)),select})},error=>{observer.error(error)})},)})}combine$.sort()对于第二点,因为排序算法很快,如果我们subscibesort()算子生成的新值开始渲染echart,页面看不到动画效果。因此,我们需要延迟echart渲染图表的过程。我们需要将sort()触发的值转换为一个异步的新事件流,并将其扁平化为原始数据流combine$.sort().flatMap(obj=>{returnRx.Observable.of(obj).delay(100*obj.select.timer++)})注意obj.select.timer++,对于sort()前后触发的两个值,为了展示echart渲染的动画,我们需要增加他们的渲染时间依次到这一步,我们的单体功能是可以正常进行的,但是如果在一个排序动画过程还没有结束的时候,我们又点击了一个新的排序类型,那么还在序列中的新旧效果图就会顺序执行,会干扰echart的渲染效果,所以在切换到新类型的时候,我们对顺序中的值进行过滤。combine$.sort().flatMap(obj=>{returnRx.Observable.of(obj).delay(100*obj.select.timer++)}).filter(x=>{returnx.select.type==currentType}).do(x=>{constoption=getOption(x.nums)echartInstance.setOption(option)}).subscribe(()=>{},null,()=>{console.log('ccomplete')})整个数据流序列-createNumber$----------------------------------------------------------------------------------------------选择$----------------------------------------------------------------------combineLatest()----------------------------合并$---------------------------------------------种类()----------------v1v2v3v4.......v11v22v33------------flatMap()----------------------------delay1delay2delay3delay4....delay11delay22delay33--------过滤器(currentType==type)--------------------------delay1delay2delay11delay22delay33--------------------------
