当前位置: 首页 > Web前端 > HTML

IoT Studio可视化搭建平台编辑历史功能的思考与探索

时间:2023-04-02 22:48:13 HTML

IoTStudio可视化构建平台编辑历史功能的思考与探索有些地方可能存在错误,这两个功能无疑为用户提供了“后悔药”。目前有各种可视化平台。本文介绍编辑历史功能的IoTStudio可视化平台的设计思路。作者|Farsaka资料来源|阿里科技公众号背景在前端可视化构建领域,“redo”和“undo”这两个功能已经是标配了。毕竟,只要有用户行为,就有可能出现问题,这两个功能无疑为用户提供了“后悔药”。目前有各种可视化平台。本文介绍编辑历史功能的IoTStudio可视化平台的设计思路。2实现思路1页面DSL维护在IoTStudio可视化构建平台中,我们通过页面的抽象语法树来维护页面状态,页面信息和组件信息记录在对应的节点上:PageNode:{componentName:'page1',id:'page1',props:{},children:[ComponentNode:{componentName:'component1',id:'component1',props:{width:800,height:1000,color:'#ffffff'},children:[]},ComponentNode:{componentName:'component2',id:'component2',props:{},children:[]},ComponentNode:{componentName:'component3',id:'component3',props:{},children:[]},]}页面保存时,页面配置会以JSON文件的形式上传到OSS。2、重做和撤消快照法每次编辑一个页面时,将页面的信息做一个深拷贝,保存在历史记录中。重做和撤销时,从历史记录中取出相应的快照,将当前页面状态替换为快照,完成一次历史记录操作。在该方法中,通常使用一个指针指向当前页面状态。如下图:后退操作后,指针指向上一个快照,页面回到P3的状态:再次编辑时,指针指向新的状态P5:快照方式的特点:实现比较简单,页面信息全面深入,复制即可。历史记录之间的切换是灵活的。当页面信息较大时,会占用大量的存储空间。命令方法IoTStudio使用这种方法。我们为每个操作定义了两个方法:execute和undo,将“操作”抽象为Operation。在execute中进行该操作的正向操作,在undo中实现反向操作。exportabstractclassOperation{/***反向操作*/protectedabstractundo():T;/***正向操作*/protectedabstractexecute():T;}每执行一次编辑操作,其实就是创建一个Operation并执行它的execute方法,如果需要再执行它的undo方法被撤销。指令方式的特点:与快照方式相比,在页面配置复杂的情况下可以节省大量的存储空间。不同Operation的execute和undo逻辑可能不同,有一定的逻辑开发成本。跨多个历史的重做或撤消要求所有执行或撤消在它们被执行之前。比如上图中从O3到O1,需要执行两次undo。这不如快照方法方便。3实现细节如上所述,IoTStudio使用指令方法。Transation在实际业务开发中,很多场景都涉及一次编辑多个组件,即多个Operation实例。所以在Operation的基础上,就有了Transaction——事务的概念。操作实例列表在事务下维护。每当执行execute或undo时,都会遍历OperationList中的Operation实例,执行其execute或undo方法。双向链表IoTStudio中的操作历史是基于双向链表实现的,每个链表节点维护一个Transaction实例。链表节点末尾的执行结果是最新的操作历史。在链表之前,通过forwardCurrent和backforwardCurrent方法切换节点状态。类管理器{backwardCurrent():boolean{if(this._current?.prev){this._current.value.operation.undo();this._current=this._current.prev;this._validLength-=1;返回真;}返回假;}forwardCurrent():boolean{if(this._current?.next){this._current.next.value.operation.execute();this._current=this._current.next;这个._validLength+=1;返回真;}返回假;}addAfterCurrent(item:OperationResult){if(nextNode){nextNode.prev=undefined;this._length=this._validLength;}this._current.next={value,prev:this._current};this._current=this._current.next;}}每当有新的编辑操作时,就会通过addAfterCurrent插入一个新的节点。4小结操作是实现redo和undo的最小指令实例。通过不同的Operation子类实现不同的execute和undo方法,从而实现redo和undo的具体逻辑。Transaction中维护了一组Operation实例。当我们在业务逻辑开发中设置组件的属性时,我们以Transaction实例为单位开发业务逻辑。维护一个双向链表来管理Transaction实例,实现可视化构建的操作历史功能。3、探索在实现思路中,我们提到了“快照法”和“命令法”。对比两者的优缺点,不难发现主要矛盾在尺寸和维护成本上。那么有没有办法兼顾两者的优点呢?下面两个工具可以提供一些思路:immutable.js+snapshot方法。JS中的对象是通过引用赋值的。保存对象时经常使用深拷贝来避免这个问题,但是这样会造成CPU和内存的浪费。这也是快照方法。缺点。不可变使用持久数据结构。在使用旧数据创建新数据时,会保证旧数据同时可用且不变。同时,为了避免深拷贝和复制所有节点带来的性能损失,immutable使用了结构共享,即如果对象树的一个节点发生变化时,只有这个节点和受其影响的父节点是修改,其他节点共享。在实现操作历史功能时,使用immutable来存储数据可以解决数据复用的问题。immutable.js+快照方法可以组合使用。据我所知,该公司的@ali/visualengine采用的就是这种方案。Git每次我们运行gitadd和gitcommit命令时,Git所做的实质是将改写后的文件保存为数据对象,更新暂存区,记录树对象。当我们使用git维护项目时,理论上随着gitcommit次数的增加,文件对象会越来越大,但实际上体积并不会变得很大。其实git在权衡了时间和空间之后,已经为我们做了一些优化。较早的版本将保存差异,较新的版本将保存全部数据对象。Git是如何做到这一点的?当Git打包一个对象时,它会寻找具有相似名称和大小的文件,并且只保存文件不同版本之间的差异。您可以查看包文件以了解它如何节省空间。同样有趣的是,第二个版本完整地保留了文件内容,而原始版本则作为差异保留-这是因为大多数情况下需要快速访问文件的最新版本。最好的部分是您可以随时重新包装。Git会时不时地自动重新打包仓库以节省空间。当然,你也可以随时手动执行gitgc命令来完成。原文链接本文为阿里云原创内容,未经许可不得转载。