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

29次阅读

共计 3304 个字符,预计需要花费 9 分钟才能阅读完成。

简介:在前端可视化搭建畛域中“重做”和“撤销”这两个性能曾经是标配中的标配,毕竟只有有用户行为的中央就可能会有出错,这两个性能无疑就是为用户提供了“后悔药”。目前有各种各样的可视化搭建平台,本文介绍 IoT Studio 可视化搭建平台在编辑历史性能上的设计与思考。

作者 | 远坂
起源 | 阿里技术公众号

一 背景

在前端可视化搭建畛域中“重做”和“撤销”这两个性能曾经是标配中的标配,毕竟只有有用户行为的中央就可能会有出错,这两个性能无疑就是为用户提供了“后悔药”。目前有各种各样的可视化搭建平台,本文介绍 IoT Studio 可视化搭建平台在编辑历史性能上的设计与思考。

二 实现思路

1 页面 DSL 的保护

在 IoT Studio 可视化搭建平台中,咱们通过页面的形象语法树来保护页面状态,页面信息和组件信息都记录在对应节点上:

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:

快照法的特点:

  • 实现比较简单,页面信息全量进行深拷贝即可。
  • 历史记录之间的切换灵便。
  • 当页面信息很大时,非常占用存储空间。

指令法

IoT Studio 应用的是这种办法。

咱们为每一次操作定义两个办法:execute 与 undo,以及将“操作”形象为 Operation。

在 execute 中执行这次操作的正向操作,在 undo 中实现逆向操作。

export abstract class Operation<T = void> {  
  /**
   * 逆向操作
   */
  protected abstract undo(): T;

  /**
   * 正向操作
   */
  protected abstract execute(): T;}

每进行一次编辑操作,其实就是创立一次 Operation 并执行其 execute 办法,随后如果须要撤销就执行其 undo 办法。

指令法的特点:

  • 绝对快照法,在页面配置简单时,能节俭不少存储空间。
  • 不同的 Operation 其 execute 和 undo 逻辑很可能会不一样,有肯定的逻辑开发成本。
  • 跨多个历史记录的重做或撤销,须要执行他们之前所有的 execute 或 undo。例如,上图中如果从 O3 到 O1 须要执行 2 次 undo。这一点没有快照法便当。

3 实现细节

在上文里提到了 IoT Studio 应用的是指令法。

Transation

在理论业务开发中,很多场景会波及到一次性编辑多个组件,即波及多个 Operation 实例。于是在 Operation 根底上有了 Transaction——事务的概念,Transaction 下保护了一份 Operation 实例 List,每当有 execute 或者 undo 执行时,会遍历 Operation List 中的 Operation 实例执行其 execute 或 undo 办法。

双向链表

IoT Studio 中的操作历史是基于双向链表实现的,每个链表节点保护一个 Transaction 实例。链表节点末端的 execute 后果既是最新的操作历史。

链表之前通过 forwardCurrent 和 backforwardCurrent 办法进行节点状态的切换。

Class Manager {backwardCurrent(): boolean {if (this._current?.prev) {this._current.value.operation.undo();

        this._current = this._current.prev;
        this._validLength -= 1;
        return true;
      }
      return false;
  }

  forwardCurrent(): boolean {if (this._current?.next) {this._current.next.value.operation.execute();

      this._current = this._current.next;
      this._validLength += 1;
      return true;
    }
    return false;
  }

  addAfterCurrent(item: OperationResult<any>) {if (nextNode) {
       nextNode.prev = undefined;
       this._length = this._validLength;
     }

     this._current.next = {value, prev: this._current};
     this._current = this._current.next;
   }
}

每当有新的编辑操作时,会通过 addAfterCurrent 插入新的节点。

4 总结

Operation 是实现重做和撤销的最小指令实例,通过 Operation 不同子类实现不同的 execute 和 undo 办法,从而实现重做和撤销的具体逻辑。

Transaction 中保护了 Operation 实例数组,咱们在进行业务逻辑开发中对组件进行属性设置时是以 Transaction 实例为单位进行业务逻辑开发。

保护了一个双向链表来对 Transaction 实例进行治理,从而实现可视化搭建的操作历史性能。

三 摸索

在实现思路中咱们提到了“快照法”和“指令法”,比照两者的优缺点,不难发现主要矛盾是在体积与保护老本上。那么有没有一种方法能兼顾二者的长处呢?上面两个工具能够提供一些思路:

immutable.js + 快照法

在 JS 中对象是援用赋值,在保留对象时往往会应用深拷贝躲避这个问题,然而这样会造成 CPU 和内存的节约,这也是快照法的毛病所在。

immutable 应用长久化数据结构,在应用旧数据创立新数据的时候,会保障旧数据同时可用且不变,同时为了防止深度复制复制所有节点的带来的性能损耗,immutable 应用了构造共享,即如果对象树种的一个节点发生变化,只批改这个节点和受他影响的父节点,其余节点则共享。

在实现操作历史性能时,应用 immutable 存储数据,能解决数据复用的问题。immutable.js + 快照法能够组合应用。据我所知公司的 @ali/visualengine 应用的就是这个计划。

Git

每次咱们运行 git add 和 git commit 命令时,Git 所做的工作本质就是将被改写的文件保留为数据对象,更新暂存区,记录树对象。

咱们在应用 git 保护我的项目时,实践上随着 git commit 的次数越来越多,文件对象会越拉越大,但实际上体积并没有变的很大。事实上 git 在衡量工夫和空间后帮咱们做了局部优化,较早的版本会保留 diff,较新的本会保留全量数据对象。

Git 是如何做到这点的?Git 打包对象时,会查找命名及大小相近的文件,并只保留文件不同版本之间的差别内容。你能够查看包文件,察看它是如何节俭空间的。

同样乏味的中央在于,第二个版本残缺保留了文件内容,而原始的版本反而是以差别形式保留的——这是因为大部分状况下须要快速访问文件的最新版本。最妙之处是你能够随时从新打包。Git 时常会主动对仓库进行从新打包以节俭空间。当然你也能够随时手动执行 git gc 命令来这么做。

原文链接
本文为阿里云原创内容,未经容许不得转载。

正文完
 0