## 写DOM的性能

Worker-DOM是在worker(WorkerGlobalScope)环境中, 实现一套DOM API, 再发到主线程执行, 工作量大，需要实例化虚拟的WorkerDOM元素， 消耗大性能低很多

这里对比了Tranel与WorkerDOM渲染2000*10的表格， 24000+个DOM节点的页面的Audits数据。   
> 测试环境： i7-6700@3.4GHz

### Adutis Metrics

**Tranel Metrics:**
![](./asserts/tranel-time.png)

**WorkerDOM Metrics:**
![](./asserts/worker-dom-time.png)

可以看到大部分指标Tranel 都是优于WorkerDOM
>说明：First Meaningful Paint 有差异是Chrome的识别有问题， 实际是差不多的, 一些基础的数据都是直出的， 可以在[Tranel Rendering Big Table](http://tranel.pages.oa.com/benchmarks/big-table/)和[Worker-DOM Rendering Big Table](http://tranel.pages.oa.com/benchmarks/big-table/worker-dom.html)自己度量。

### 首屏数据

**Tranel 首屏:**
![](./asserts/tranel-render.png)

**WorkerDOM 首屏:**
![](./asserts/worker-dom-render.png)


由于指令生成时间Tranel的整体Proxy机制比WorkerDOM的逐个实现性能好很多(45ms vs 500ms 10倍以上), 由上图可以看到，首屏时间Tranel比WorkerDOM快一倍以上。 

> 说明: 两者都有 580ms的卡帧， 是24000个DOM节点的插入渲染时间， 正常应用只会插入几百个节点，时间非常短(10+ms)。 


### Tranel进阶的优化

目前Tranel根据Worker的需要`生成指令`，`传输指令` 特点做了两个维度的优化， 性能比上面的初始对比更好。
1. 批量处理创建DOM、设置属性和内容， 支持克隆节点
API如下：
```typescript
    createElement(from: string | Element, attrs: {
        [key: string]: string | number;
    } | null | undefined, children?: Array<Element | string> | string): Element;
```

在这个例子中可节省83%+的指令。 减少50的指令生成时间和传输时间。 例子：[batch](http://tranel.pages.oa.com/benchmarks/big-table/tranel-turbo.html)

2. 用更易传输的简单的格式表示DOM
格式定义如下： 

```typescript
type CloneBaseID = string;
type IsDefineBase = boolean;
export interface ITreeDescriptionArray extends Array<TreeDescription> { }
export type TreeDescription = [
  string,
  {[key: string]: string | number} | undefined,
  ITreeDescriptionArray | undefined | string,
  CloneBaseID?, // cloneBaseID 克隆的性能比新建好很多
  IsDefineBase? // isDefineBase
];
```

具体为：
```typescript
  createDOMTree(treeDesc: TreeDescription, parent?: Node | undefined): Node; //定义
   turbo.createDOMTree(["div", undefined, [
    ["h3", {class: 1}, "xxxx"],
      ["div", {class: 1}, [
      ["h5", undefined, "im title 5"]
      ]],
   ]])
```

直接定义DOM树并拿到引用， 生成和传输的指令更少， 性能更佳。 例子：[createDOMTree](http://tranel.pages.oa.com/benchmarks/big-table/tranel-turbo.html)



### 正常使用
以上均为暴力测试， 正常业务情况下一部只会渲染首屏， 后面几屏逐步加载， 示例： [逐步加载](http://tranel.pages.oa.com/benchmarks/big-table/tranel-normal.html)


## 读DOM的性能
读DOM的性能WorkerDOM优于Tranel：
1. 对于渲染无关的属性，WorkerDOM只需读本地缓存或计算即可。Tranel需要从主线程取(1~2ms左右的时延 + 一个tick)， 比如textContext, WorkerDOM的实现为：

```typescript
 get textContent(): string {
    let textContent = '';
    const childNodes = this.childNodes;

    if (childNodes.length) {
      childNodes.forEach(childNode => (textContent += childNode.textContent));
      return textContent;
    }
    return '';
  }
```
2. 对于渲染相关的属性，WorkerDOM暂未实现， 无法读取， Tranel也是主线程取， 如果WorkerDOM实现后性能应该差不多。
比如scrollTop, WorkerDOM 不可能在Worker中再计算布局， 成本太高。


由于读DOM一般为用户事件(click， touch)触发，10ms不到的时延对于的100ms内的推荐响应时间可以接受。 
对于虚拟DOM的场景可以在Worker中维护一个虚拟DOM树， 不会影响对比时间。
具体的读DOM的性能需要进一步的对比。



## 总结

总的来说：
1. 写性能Tranel优于WorkerDOM, 对于页面初始化时写比较多的场景优势很大， 具体表现为首屏时间Tranel快WorkerDOM一倍以上;
2. 读性能WorkerDOM优于Tranel，事件响应等可能需要读DOM的场景相对WorkerDOM慢几ms， 虚拟DOM不受影响。