3

引言

还是性能的问题,数据量大的时候,特别得卡。

clipboard.png

上算法课,也没找到一种性能很优的算法,最终使用Map重新设计了一下,并使用原生的checkbox,性能有极大地提升,用户感觉不出任何卡顿。

优化实践

原组件性能分析

<nz-checkbox-wrapper style="width: 100%;" (nzOnChange)="change($event)">
    <div nz-row>
        <div nz-col nzSpan="4" *ngFor="let host of hostListValues">
            <label nz-checkbox [nzValue]="host.value"
                   [(ngModel)]="host.checked">{{host.label}}</label>
        </div>
    </div>
</nz-checkbox-wrapper>
this.hostService.getAllHosts().subscribe((hosts) => {
    this.hostListValues = [];
    // 获取主机数量
    const length = hosts.length;
    // 使用主机信息构造多选框绑定数据
    for (let index = 0; index < length; index++) {
        this.hostListValues.push({
            label: hosts[index].name,
            value: hosts[index],
            checked: HostCheckboxComponent.existIn(hosts[index], this._hostList)
        });
    }
});
  1. 根据计算机列表构造符合规范的数组(每次循环都需要判断是否选中)。
  2. htmlngFor
  3. 每点击一次,就输出一次nzOnChange事件,因为该事件的参数是当前选中的计算机列表,所以应该也进行循环了。

使用原生checkbox

使用原生的checkbox,我们就不需要再去循环构建符合ng zorro要求格式的数据了,直接就把计算机列表传给页面。

<nz-row>
    <nz-col *ngFor="let host of hosts" [nzSpan]="4">
        <label>
            <input type="checkbox">
            {{ host.name }}
        </label>
    </nz-col>
</nz-row>

默认选中的设计

原来的默认选中复杂度太高。

假设2000台计算机,100个默认选中的,最终执行次数就是2000 * 100

for 计算机列表
  for 默认选中计算机列表

怎样降低复杂度呢?

最终想到了使用Map,毕竟Map查询的复杂度是要比自己for循环低的多的。设计一个checkedMap,该Map中存储了所有被选中的主机的id

/**
 * 计算机选中的Map存储
 */
public checkedMap: Map<number, boolean>;
<nz-row>
    <nz-col *ngFor="let host of hosts" [nzSpan]="4">
        <label>
            <input type="checkbox" (change)="syncHostCheckedMap(host.id)" [checked]="checkedMap.get(host.id)">
            {{ host.name }}
        </label>
    </nz-col>
</nz-row>

再分析一下,2000台计算机,100台默认选中的,因为Native Map的高性能,应该能提升部分性能。

组件输出

@Output()
hostCheck = new EventEmitter<Array<Host>>();

因为多选框写成了组件,组件其实并不知道用我的页面什么时候要我的数据,所以使用事件输出的,当用户选中的内容有变化时,我就for循环一次所有的计算机,然后把选中的输出出去。

现在则是写一个public方法,供外部调用。

/**
 * 获取所有选中的计算机列表
 * 供外部调用
 */
public getAllCheckedHostList(): Array<Host> {
    // 初始化计算机列表
    const hostList: Array<Host> = new Array<Host>();
    // 遍历选中的Map
    this.checkedMap.forEach((value, key) => {
        // 遍历计算机列表
        this.hosts.forEach((host) => {
            // 如果符号位,添加到列表中
            if (host.id === key) {
                hostList.push(host);
            }
        });
    });
    // 返回
    return hostList;
}

怎么调的呢?以下是示例代码:

<app-host-checkbox #hostCheckbox [primaryHostList]="primaryHostList"></app-host-checkbox>
/**
 * 获取HostCheckboxComponent组件
 */
@ViewChild('hostCheckbox')
private hostCheckbox: HostCheckboxComponent;
/**
 * 计算机组更新方法
 * @param hostGroup 计算机组
 */
public update(hostGroup: HostGroup): void {
    // 从组件中拿去选中的计算机的列表
    hostGroup.hostList = this.hostCheckbox.getAllCheckedHostList();
    // 请求后台更新计算机组
}

ViewChild - Angular.io

Angular官网说ViewChild用于视图查询,我理解就是把用到的组件注进来,和组件的交互不仅限于输入输出,还可以调用组件对外暴露的方法。

总结

当编码已经不成问题的时候,我们真正可以当语言为工具,通过我们的思考,构造一个又一个实用的设计。


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。