最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Tree組件實(shí)現(xiàn)支持50W數(shù)據(jù)方法剖析

 更新時(shí)間:2022年08月11日 08:48:18   作者:誰(shuí)說(shuō)不啊  
這篇文章主要為大家介紹了Tree組件實(shí)現(xiàn)支持50W數(shù)據(jù)的方法剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

出師未捷身先死

有用戶在 fes-design VIP群 吐槽 Tree 組件在處理一萬(wàn)條左右數(shù)據(jù)時(shí)很卡。但是 fes-design 已重視大數(shù)據(jù)場(chǎng)景,提供基礎(chǔ)的虛擬列表組件,以及選擇器、表格、樹(shù)形、級(jí)聯(lián)等組件基于虛擬列表處理了大數(shù)據(jù)場(chǎng)景,為啥 Tree 組件還卡呢?

Tree 自身的復(fù)雜性

Tree 數(shù)據(jù)結(jié)構(gòu)特性決定 Tree 組件中父子節(jié)點(diǎn)存在關(guān)聯(lián),以選中功能為例:

Select:選中只影響自身狀態(tài)。

Tree:當(dāng)開(kāi)啟父子關(guān)聯(lián)時(shí),選中某個(gè)節(jié)點(diǎn)時(shí),其所有子孫節(jié)點(diǎn)全部選中,同時(shí)需計(jì)算父輩節(jié)點(diǎn)是否為全選中。

虛擬滾動(dòng)帶來(lái)的復(fù)雜性

虛擬滾動(dòng)是指根據(jù)滾動(dòng)距離計(jì)算當(dāng)前視野范圍需要展示的內(nèi)容。不管有多少數(shù)據(jù),只渲染視野范圍內(nèi)的選項(xiàng),大大減少了 Vue 實(shí)例的創(chuàng)建,性能無(wú)比優(yōu)越。因?yàn)樘摂M滾動(dòng)只接受一維數(shù)組結(jié)構(gòu),所以Tree 組件在初始化時(shí)需要把樹(shù)狀結(jié)構(gòu)數(shù)據(jù)按照展示順序拍平為一維數(shù)組。那么展開(kāi)關(guān)閉的功能就變得復(fù)雜了!

不考慮虛擬滾動(dòng)方案時(shí)節(jié)點(diǎn)會(huì)這么設(shè)計(jì):

<div class="node">
    <div>{{ node.label }}</div>
    <div v-show="node.expanded" v-for="child in node.children">
            <Node node="child"/> 
    </div>
</div>

展開(kāi)關(guān)閉只需要改變 node.expanded

考慮虛擬滾動(dòng)方案時(shí)節(jié)點(diǎn)會(huì)這么設(shè)計(jì):

<div class="node">
    <div>{{ node.label }}</div>
</div>

計(jì)算所有子孫節(jié)點(diǎn)狀態(tài),判斷節(jié)點(diǎn)是否顯示,如果顯示則把當(dāng)前節(jié)點(diǎn)丟到虛擬滾動(dòng)的一維數(shù)組中。

查問(wèn)題

先用chrome的性能測(cè)試工具看看問(wèn)題在哪:

可以找到耗時(shí)的代碼語(yǔ)句,下一步干掉他們。

怎么做

緩存數(shù)據(jù)

Tree 組件在初始化時(shí)會(huì)把樹(shù)狀結(jié)構(gòu)數(shù)據(jù)按照展示順序拍平為一維數(shù)組,在這個(gè)過(guò)程中,記錄每個(gè)節(jié)點(diǎn)的父級(jí)節(jié)點(diǎn)為indexPath 和所有子孫節(jié)點(diǎn)childrenPath。在后續(xù)邏輯中經(jīng)常會(huì)用到:

// 當(dāng)選中某個(gè)節(jié)點(diǎn)時(shí),只需要處理此節(jié)點(diǎn)相關(guān)上下節(jié)點(diǎn)狀態(tài)
if (checkingNode) {
    const { indexPath } = checkingNode;
    indexPath.slice(0).reverse().forEach(computeIndeterminate);
    checkingNode.hasChildren &&
        checkingNode.childrenPath.forEach(
            (key: TreeNodeKey) => {
                const node = nodeList.get(key);
                node.isIndeterminate.value = false;
            },
        );
    checkingNode = null;
}

減少響應(yīng)式數(shù)據(jù)

在優(yōu)化前所有節(jié)點(diǎn)都會(huì)丟到nodeList中:

const nodeList = reactive<TreeNodeList>({});

// 轉(zhuǎn)換節(jié)點(diǎn)數(shù)據(jù)
const copy = transformNode(node, indexPath, level);
nodeList[copy.value] = copy;

數(shù)據(jù)量上來(lái)后,數(shù)據(jù)響應(yīng)式處理耗時(shí)非常大。所以我們不要把整個(gè)對(duì)象一股腦弄成響應(yīng)式的,只把需要的字段設(shè)置為響應(yīng)式的。

Tree節(jié)點(diǎn)需要緩存的內(nèi)部狀態(tài)有是否開(kāi)展、是否全選、是否選中,所以只需要這三個(gè)字段為響應(yīng)式:

const nodeList: Map<TreeNodeKey, InnerTreeOption> = new Map();

f (!nodeList.get(value)) {
    // Object.assign比解構(gòu)快很多
    copy = Object.assign({}, newItem);
    copy.isExpanded = ref(false);
    copy.isIndeterminate = ref(false);
    copy.isChecked = ref(false);
}

nodeList.set(copy.value, copy);

用更快的 JS 語(yǔ)法

1、Array.concat 性能比較慢,改為使用賦值

export function concat(arr: any[], arr2: any[]) {
    const arrLength = arr.length;
    const arr2Length = arr2.length;
    arr.length = arrLength + arr2Length;
    for (let i = 0; i < arr2Length; i++) {
    arr[arrLength + i] = arr2[i];
    }
    return arr;
}

2、Map 的查找性能比 Object 稍好

const nodeList = {} ;

改為使用

const nodeList = new Map();

3、解構(gòu)語(yǔ)法比較慢,改為使用Object.assign

扣細(xì)節(jié)

1、computeCurrentData 是執(zhí)行非常耗時(shí)的函數(shù),由于 watch 兩個(gè)變量,在初始化時(shí)會(huì)執(zhí)行兩次,加上debounce只需要執(zhí)行一次。

watch(
    [currentExpandedKeys, transformData],
    debounce(() => {
        if (isSearchingRef.value) return;
        computeCurrentData();
    }, 10),
    {
        immediate: true,
    },
);

2、葉子節(jié)點(diǎn)不需要計(jì)算isExpanded

 if (node.hasChildren) {
    node.isExpanded.value = expandedKeys.includes(key);
 }

3、計(jì)算顯示的節(jié)點(diǎn)時(shí),可以先判斷是否由展開(kāi)或者關(guān)閉節(jié)點(diǎn)觸發(fā)的計(jì)算,如果是則只需要計(jì)算此節(jié)點(diǎn)子孫和父級(jí)節(jié)點(diǎn)狀態(tài),而不需要計(jì)算全部節(jié)點(diǎn)

const computeCurrentData = ()=> {
    if(expandingNode) {
        // 計(jì)算此節(jié)點(diǎn)相關(guān)節(jié)點(diǎn)
        return
    }
    // 遍歷所有節(jié)點(diǎn)
}

類似這種細(xì)節(jié)非常多,通過(guò)性能測(cè)試工具和自己經(jīng)驗(yàn)?zāi)苷业胶芏嗟胤剑e少成多,性能能提升不少。

數(shù)據(jù)結(jié)構(gòu)一致性的魅力

以收起節(jié)點(diǎn)為例:

常規(guī)思路是:當(dāng)點(diǎn)擊收起節(jié)點(diǎn)時(shí),判斷當(dāng)前所有子孫節(jié)點(diǎn)是否在顯示數(shù)據(jù)數(shù)組中,如果在就刪掉。復(fù)雜度是O(n^2)。

但是可以換個(gè)思路:由于childrenPath和currentData的順序一致,只需要遍歷一次childrenPath,判斷是是否為當(dāng)前節(jié)點(diǎn)下一個(gè)節(jié)點(diǎn),如果是,刪掉就好。復(fù)雜度是O(n)

const deleteNode = (keys: TreeNodeKey[], index: number) => {
    let len = 0;
    keys.forEach((key) => {
        if (key === currentData.value[index + len]) {
            len += 1;
        }
    });
    currentData.value.splice(index, len);
};

const index = currentData.value.indexOf(expandingNode.value);
deleteNode(expandingNode.childrenPath, index + 1);

Tree 的代碼中有很多地方,可以通過(guò)特殊的數(shù)據(jù)結(jié)構(gòu)來(lái)減少或者避免循環(huán),性能提升非常大!

歡迎來(lái)體驗(yàn): fes-design

以上就是Tree組件實(shí)現(xiàn)支持50W數(shù)據(jù)方法剖析的詳細(xì)內(nèi)容,更多關(guān)于Tree組件50W數(shù)據(jù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 簡(jiǎn)單了解Java多態(tài)向上轉(zhuǎn)型相關(guān)原理

    簡(jiǎn)單了解Java多態(tài)向上轉(zhuǎn)型相關(guān)原理

    這篇文章主要介紹了簡(jiǎn)單了解Java多態(tài)向上轉(zhuǎn)型相關(guān)原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • java壓縮多個(gè)文件并且返回流示例

    java壓縮多個(gè)文件并且返回流示例

    這篇文章主要介紹了java壓縮多個(gè)文件并且返回流示例,返回壓縮流主是為了在程序里再做其它操作,需要的朋友可以參考下
    2014-03-03
  • springBoot2.6.2自動(dòng)裝配之注解源碼解析

    springBoot2.6.2自動(dòng)裝配之注解源碼解析

    對(duì)于springboot個(gè)人認(rèn)為它就是整合了各種組件,然后提供對(duì)應(yīng)的自動(dòng)裝配和啟動(dòng)器(starter),基于這個(gè)流程去實(shí)現(xiàn)一個(gè)定義的裝配組件,下面這篇文章主要給大家介紹了關(guān)于springBoot2.6.2自動(dòng)裝配之注解源碼解析的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • springboot集成kafka消費(fèi)手動(dòng)啟動(dòng)停止操作

    springboot集成kafka消費(fèi)手動(dòng)啟動(dòng)停止操作

    這篇文章主要介紹了springboot集成kafka消費(fèi)手動(dòng)啟動(dòng)停止操作,本文給大家介紹項(xiàng)目場(chǎng)景及解決分析,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 解決SpringBoot文件上傳臨時(shí)目錄找不到的問(wèn)題

    解決SpringBoot文件上傳臨時(shí)目錄找不到的問(wèn)題

    這篇文章主要介紹了解決SpringBoot文件上傳臨時(shí)目錄找不到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索

    JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索

    本文主要介紹了JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • 啟動(dòng)springboot應(yīng)用因未配置數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方案

    啟動(dòng)springboot應(yīng)用因未配置數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方案

    這篇文章主要介紹了啟動(dòng)springboot應(yīng)用因未配置數(shù)據(jù)庫(kù)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringCloud?OpenFeign概述與使用教程

    SpringCloud?OpenFeign概述與使用教程

    OpenFeign源于Netflix的Feign,是http通信的客戶端。屏蔽了網(wǎng)絡(luò)通信的細(xì)節(jié),直接面向接口的方式開(kāi)發(fā),讓開(kāi)發(fā)者感知不到網(wǎng)絡(luò)通信細(xì)節(jié)。所有遠(yuǎn)程調(diào)用,都像調(diào)用本地方法一樣完成
    2023-02-02
  • 基于SpringBoot和PostGIS的某國(guó)基地可視化實(shí)戰(zhàn)

    基于SpringBoot和PostGIS的某國(guó)基地可視化實(shí)戰(zhàn)

    本文以Java開(kāi)發(fā)語(yǔ)言為例,使用SpringBoot框架來(lái)進(jìn)行后臺(tái)開(kāi)發(fā),詳細(xì)講解如何使用Leaflet對(duì)PostGIS的全球基地信息進(jìn)行Web可視化,最后分享Web可視化結(jié)果,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java 創(chuàng)建線程的四種方式

    java 創(chuàng)建線程的四種方式

    這篇文章主要介紹了java 創(chuàng)建線程的四種方式,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-11-11

最新評(píng)論

乐亭县| 北京市| 克什克腾旗| 田林县| 宝鸡市| 三门县| 汉寿县| 建瓯市| 永川市| 垦利县| 洪江市| 井研县| 宜州市| 灌南县| 平潭县| 吉水县| 康保县| 房产| 霍州市| 农安县| 尚志市| 兴城市| 卢湾区| 平乡县| 邯郸市| 湘乡市| 高青县| 潼关县| 电白县| 萍乡市| 广德县| 岑巩县| 从化市| 通化市| 文昌市| 饶阳县| 周宁县| 永川市| 墨竹工卡县| 长乐市| 乐陵市|