Nani? The backend needs to return me 100000 pieces of data at once! Let's take a look at my eight clever solutions

10what the f**k!.


  • 10
  • what the f**k!

...

  • ......

express

expressVue+Express+Mysql

jsroute.get("/bigData", (req, res) => {  res.header('Access-Control-Allow-Origin', '*'); //   let arr = [] //   for (let i = 0; i < 100000; i++) { //     arr.push({      id: i + 1,      name: '' + (i + 1),      value: i + 1,    })  }  res.send({ code: 0, msg: '', data: arr }) // })

html

html<el-button :loading="loading" @click="plan"></el-button><el-table :data="arr">  <el-table-column type="index" label="" />  <el-table-column prop="id" label="ID" />  <el-table-column prop="name" label="" />  <el-table-column prop="value" label="" /></el-table>data() {    return {      arr: [],      loading: false,    };},async plan() {    // arr}

10

js async plan() {      this.loading = true;      const res = await axios.get("http://ashuai.work:10000/bigData");      this.arr = res.data.data;      this.loading = false;}

  • 210
  • 1010
  • 10

  • 10
  • 100~910~19
  • [1,2,3,4,5,6,7]
  • 3
  • [ [1,2,3], [4,5,6], [7]]

10

jsfunction averageFn(arr) {  let i = 0; // 1. 0  let result = []; // 2.   while (i < arr.length) { // 6.     // 3.     result.push(arr.slice(i, i + 10)); // 4. 10    i = i + 10; // 5. 10  }  return result; // 7. }

js  async plan() {      this.loading = true;      const res = await axios.get("http://ashuai.work:10000/bigData");      this.loading = false;      let twoDArr = averageFn(res.data.data);      for (let i = 0; i < twoDArr.length; i++) {        //         setTimeout(() => {          this.arr = [...this.arr, ...twoDArr[i]]; //         }, 1000 * i); // 17 * i // ... 17 = 1000 / 60      }    },

requestAnimationFrame

requestAnimationFramerequestAnimationFrame

plan

jsasync plan() {  this.loading = true;  const res = await axios.get("http://ashuai.work:10000/bigData");  this.loading = false;  // 1.   let twoDArr = averageFn(res.data.data);  // 2.   const use2DArrItem = (page) => {    // 4.     if (page > twoDArr.length - 1) {      console.log("");      return;    }    // 5.     requestAnimationFrame(() => {      // 6. concat      this.arr = [...this.arr, ...twoDArr[page]];      // 7.       page = page + 1;      // 8.       use2DArrItem(page);    });  };  // 3. 0  use2DArrItem(0); },

jsgetShowTableData() {     //      let begin = (this.pageIndex - 1) * this.pageSize;     //      let end = this.pageIndex * this.pageSize;     //     this.showTableData = this.allTableData.slice(begin, end); }

500MB5010MB......

  • scrollTop + clientHeight >= innerHeight
  • new MutationObserver()


v-el-table-infinite-scrollnpmwww.npmjs.com/package/el-

vue-scroller

el-tableel-table-infinite-scroll

vue2vue3

cnpm install --save [email protected]

js// import elTableInfiniteScroll from 'el-table-infinite-scroll';Vue.use(elTableInfiniteScroll);

el-table

js<el-table  v-el-table-infinite-scroll="load"  :data="tableData">  <el-table-column prop="id" label="ID"></el-table-column>  <el-table-column prop="name" label=""></el-table-column></el-table>async load() {    // ...},

html<template>  <div class="box">    <el-table      v-el-table-infinite-scroll="load"      height="600"      :data="tableData"      border      style="width: 80%"      v-loading="loading"      element-loading-text="..."      element-loading-spinner="el-icon-loading"      element-loading-background="rgba(255, 255, 255, 0.5)"      :header-cell-style="{        height: '24px',        lineHeight: '24px',        color: '#606266',        background: '#F5F5F5',        fontWeight: 'bold',      }"    >      <el-table-column type="index" label=""></el-table-column>      <el-table-column prop="id" label="ID"></el-table-column>      <el-table-column prop="name" label=""></el-table-column>      <el-table-column prop="value" label=""></el-table-column>    </el-table>  </div></template><script>// function averageFn(arr) {  let i = 0;  let result = [];  while (i < arr.length) {    result.push(arr.slice(i, i + 10)); // 10    i = i + 10; // 1010  }  return result;}import axios from "axios";export default {  data() {    return {      allTableData: [], //       tableData: [], //       loading: false    };  },  //   async created() {    this.loading = true;    const res = await axios.get("http://ashuai.work:10000/bigData");    this.allTableData = averageFn(res.data.data); //     // this.originalAllTableData = this.allTableData //     this.loading = false;    //     this.load();   },  methods: {    //     async load() {      console.log("");      // return      if (this.allTableData.length == 0) {        console.log("");        return;      }      //       let arr = this.allTableData[0];      this.tableData = this.tableData.concat(arr);      //       this.allTableData.shift();    },  },};</script>

/

  • 10dom
  • dom

GitHub

html<template>  <!--             104010400            400 -->  <div    class="virtualListWrap"    ref="virtualListWrap"    @scroll="handleScroll"    :style="{ height: itemHeight * count + 'px' }"  >    <!-- dom -->    <div      class="placeholderDom"      :style="{ height: allListData.length * itemHeight + 'px' }"    ></div>    <!-- 10top -->    <div class="contentList" :style="{ top: topVal }">      <!--  -->      <div        v-for="(item, index) in showListData"        :key="index"        class="itemClass"        :style="{ height: itemHeight + 'px' }"      >        {{ item.name }}      </div>    </div>    <!--  -->    <div class="loadingBox" v-show="loading">      <i class="el-icon-loading"></i>        <span>loading...</span>    </div>  </div></template><script>import axios from "axios";export default {  data() {    return {      allListData: [], //       itemHeight: 40, // 40      count: 10, //       start: 0, //       end: 10, //       topVal: 0, // top      loading: false,    };  },  computed: {    // allListDatashowListData    showListData: function () {      return this.allListData.slice(this.start, this.end);    },  },  async created() {    this.loading = true;    const res = await axios.get("http://ashuai.work:10000/bigData");    this.allListData = res.data.data;    this.loading = false;  },  methods: {    //     handleScroll() {      /**       * Element.scrollTop       *       *        * 40.84/0.8 = 5       *       * 10       * ,  + size==,        * */      const scrollTop = this.$refs.virtualListWrap.scrollTop;      this.start = Math.floor(scrollTop / this.itemHeight);      this.end = this.start + this.count;      /**       * top       * */      this.topVal = this.$refs.virtualListWrap.scrollTop + "px";    },  },};</script><style scoped lang="less">// .virtualListWrap {  box-sizing: border-box;  width: 240px;  border: solid 1px #000000;  //   overflow-y: auto;  //   position: relative;  .contentList {    width: 100%;    height: auto;    //     position: absolute;    top: 0;    left: 0;    .itemClass {      box-sizing: border-box;      width: 100%;      height: 40px;      line-height: 40px;      text-align: center;    }    //     .itemClass:nth-child(even) {      background: #c7edcc;    }    .itemClass:nth-child(odd) {      background: pink;    }  }  .loadingBox {    position: absolute;    top: 0;    left: 0;    right: 0;    bottom: 0;    width: 100%;    height: 100%;    background-color: rgba(255, 255, 255, 0.64);    color: green;    display: flex;    justify-content: center;    align-items: center;  }}</style>

vxetable

tableUIvxetable

vue2vue3 5w 30w

vxetable.cn/v3/#/table/

cnpm i xe-utils [email protected] --save

main.js

js// VXETableimport VXETable from 'vxe-table'import 'vxe-table/lib/style.css'Vue.use(VXETable)

html<template>  <div class="box">    <vxe-table      border      show-overflow      ref="xTable1"      height="300"      :row-config="{ isHover: true }"      :loading="loading"    >      <vxe-column type="seq"></vxe-column>      <vxe-column field="id" title="ID"></vxe-column>      <vxe-column field="name" title=""></vxe-column>      <vxe-column field="value" title=""></vxe-column>    </vxe-table>  </div></template><script>import axios from "axios";export default {  data() {    return {      loading: false,    };  },  async created() {    this.loading = true;    const res = await axios.get("http://ashuai.work:10000/bigData");    this.loading = false;    this.render(res.data.data);  },  methods: {    render(data) {      this.$nextTick(() => {        const $table = this.$refs.xTable1;        $table.loadData(data);      });    },  },};</script>

Web Worker

Web Worker

Web Workervue-workerWeb Worker

...

7


10

7

1010

****sqllimitdom

...

...

UI

2200007...

...

lighthousechromedevtoolPerformance

4000lighthousechormePerformance

lighthouse

lighthouseWeb

19

lighthouse

lighthouse

lighthousejs

  • 9.4s
    • 14
    • js7.2s
  • dom
  • 24530domdommarkerdomdomdom
  • 48kb1.3s

lighthouse

  • 14
  • dom
  • 1.4s

lighthousechrome devtoolPerformance

Performance

PerformancePerformancemain

  • htmljscomposite layers
  • js

chrome Performance

10sjs7.6sjsMicrotasks3.4s_next3.94sfulfilled

  • _nextmarker

  • fulfilled_nextmarkerpopupdommarkerpopuphtml

fulfilledmarkerpopup

lighthousePerformance:

  • markerdomdom
  • marker_next

  • dommarkercanvas
  • marker

n

diffdemo

code.juejin.cn/pen/7142775

  • dom
  • requestAnimationFrame10

DOMdom

  • React

antddemo

4000

_next1sjs4621ms

markerdomdomleafletcanvascanvasdomHTMLCanvas]

markermarkerpopupleafletplugins Leaflet.Canvas-Markersmarkermarkerdemo

marker

jsx<MapContainer {...props}>   {       stops.map((stop) => {         return <CustomMarker key={stop.id} data={stop} />;        })    } </MapContainer>  // CustomMarker function CustomMarker(props) {     ...     // react-leafletMarkerDom     <Marker      ...      position={position}    >      <Popup        {...props}      >        ... // popup      </Popup>    </Marker> }

jsx // render <MapContainer {...props}>   <CanvasMarkers data={stops} /> </MapContainer>  // CanvasMarkers import 'leaflet-canvas-marker'; function CanvasMarkers({data}) {        const map = useMap();      const canvasLayerRef = useRef();      const icon = window.L.icon({      iconUrl: '',      iconSize: [8, 8],      iconAnchor: [4, 4],    });      useEffect(() => {        if (!data.length) {          canvasLayerRef.current?.onRemove(map);          return;        }        canvasLayerRef.current = window.L.canvasIconLayer({}).addTo(map);        const canvasMarkers = [];        for (let i = 0, len = data.length; i < len; i++) {          const { lat, lng } = data[i];          const marker = window.L.marker([lat, lng], {            icon,          }).bindPopup(popupHtml);          canvasMarkers.push(marker);        }        canvasLayerRef.current?.addLayers(canvasMarkers);      }, [markers, icon, map]);      return null; }

dommarkercanvas

4000canvas

fulfilled100msjs1102mscanvas

4000Performancejs7.4s75%

  • 1
  • jsx
  • // table setTableData(tableData); // setTableDatareactuseState setTimeout(() => { // 100ms setMarkers(stops); // setMarkersreactuseState }, 100);
  • 2
  • CanvasMarkers
  • jsx
import 'leaflet-canvas-marker'; function CanvasMarkers({data}) { ... const [data, setData] = useState([]); // marker const sliceData = useCallback((list, index: number = 0, num = 100) => { const endIdx = Math.ceil(list.length / num); if (index === endIdx) { return; } setTimeout(() => { // 200ms const toBeRenderList = list.slice(index * num, (index + 1) * num); setData(toBeRenderList); console.log(toBeRenderList, toBeRenderList.length); sliceData(list, index + 1, num); }, 200); }, []); useEffect(() => { const len = markers.length; if (len === 0) { canvasLayerRef.current?.onRemove(map); return; } canvasLayerRef.current = window.L.canvasIconLayer({}).addTo(map); //  const sliceLen = len > 100000 ? 2000 : len > 50000 ? 1000 : 500; sliceData(data, 0, sliceLen); }, [markers, map, sliceData]); // dataL.marker useEffect(() => { if (!data.length) { return; } const canvasMarkers = []; for (let i = 0, len = data.length; i < len; i++) { const { lat, lng } = data[i]; const marker = window.L.marker([lat, lng], { icon, }).bindPopup(popupHtml); canvasMarkers.push(marker); } canvasLayerRef.current?.addLayers(canvasMarkers); }, [data, map]); return null; }

5Performance

TBT: 2690ms1045ms60% 4.5s6.1s1.6s

4000

  • js7453ms1466ms
  • 9979ms2999ms

  • ashuai.work:8888/#/bigData
  • GitHubgithub.com/shuirongshu


Disclaimer: The content of this article is sourced from the internet. The copyright of the text, images, and other materials belongs to the original author. The platform reprints the materials for the purpose of conveying more information. The content of the article is for reference and learning only, and should not be used for commercial purposes. If it infringes on your legitimate rights and interests, please contact us promptly and we will handle it as soon as possible! We respect copyright and are committed to protecting it. Thank you for sharing.(Email:[email protected])