How can the front end better display the 100,000 pieces of data returned by the back end?

How can the front end better display the 100,000 pieces of data returned by the back end?

Let’s talk about this today. If the backend really returns 100,000 pieces of data to the frontend, how can we display them elegantly on the frontend?

Preliminary work

Do the preliminary work first, then you can test it later.

Backend construction

Create a new server.js file, start a simple service, return 10w pieces of data to the front end, and start the service through nodemon server.js

If nodemon is not installed, you can install it globally first with npm i nodemon -g

// server.js
const http = require('http')
const port = 8000; 
http.createServer(function (req, res) {
  // Enable Cors
  res.writeHead(200, {
    //Set the domain name allowed across domains. You can also set * to allow all domain names. 'Access-Control-Allow-Origin': '*',
    //Cross-domain allowed request methods, you can also set * to allow all methods "Access-Control-Allow-Methods": "DELETE,PUT,POST,GET,OPTIONS",
    //Allowed header types 'Access-Control-Allow-Headers': 'Content-Type'
  })
  let list = []
  let num = 0
 
  // Generate a list of 100,000 records
  for (let i = 0; i < 1000000; i++) {
    num++
    list.push({
      src: 'https://p3-passport.byteacctimg.com/img/user-avatar/d71c38d1682c543b33f8d716b3b734ca~300x300.image',
      text: `I am guest number ${num} Lin Sanxin`,
      tid: num
    })
  }
  res.end(JSON.stringify(list));
}).listen(port, function () {
  console.log('server is listening on port ' + port);
})

Front-end page

First create a new index.html

// index.html
// Style <style>
    * {
      padding: 0;
      margin: 0;
    }
    #container {
      height: 100vh;
      overflow:auto;
    }
    .sunshine {
      display: flex;
      padding: 10px;
    }
    img {
      width: 150px;
      height: 150px;
    }
  </style> 
// html part <body>
  <div id="container">
  </div>
  <script src="./index.js"></script>
</body>

Then create a new index.js file and encapsulate an AJAX function to request these 10w data

// index.js 
// Request function const getList = () => {
    return new Promise((resolve, reject) => {
        //Step 1: Create asynchronous object var ajax = new XMLHttpRequest();
        //Step 2: Set the request URL parameters. Parameter 1 is the request type, and parameter 2 is the request URL. You can use ajax.open('get', 'http://127.0.0.1:8000');
        //Step 3: Send request ajax.send();
        //Step 4: Register the onreadystatechange event. When the state changes, ajax.onreadystatechange = function () {
            if (ajax.readyState == 4 && ajax.status == 200) {
                //Step 5 If you can get to this point, it means the data is returned perfectly and the requested page exists resolve(JSON.parse(ajax.responseText))
            }
        }
    })
} 
// Get the container object const container = document.getElementById('container')

Direct Rendering

The most direct way is to render it directly, but this approach is definitely not advisable, because rendering 10w nodes at a time is very time-consuming. Let's take a look at the time consumption. It takes about 12秒, which is very time-consuming.

const renderList = async () => {
    console.time('list time')
    const list = await getList()
    list.forEach(item => {
        const div = document.createElement('div')
        div.className = 'sunshine'
        div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
        container.appendChild(div)
    })
    console.timeEnd('list time')
}
renderList()

setTimeout paging rendering

This method is to divide 10w into a total of Math.ceil(total / limit) pages according to limit the number of pages per page, and then use setTimeout to render one page of data each time. In this way, the time to render the home page data is greatly reduced.

const renderList = async () => {
    console.time('list time')
    const list = await getList()
    console.log(list)
    const total = list.length
    const page = 0
    const limit = 200
    const totalPage = Math.ceil(total / limit) 
    const render = (page) => {
        if (page >= totalPage) return
        setTimeout(() => {
            for (let i = page * limit; i < page * limit + limit; i++) {
                const item = list[i]
                const div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                container.appendChild(div)
            }
            render(page + 1)
        }, 0)
    }
    render(page)
    console.timeEnd('list time')
}

requestAnimationFrame

Using requestAnimationFrame instead of setTimeout reduces the number of重排and greatly improves performance. It is recommended that you use requestAnimationFrame more often in rendering.

const renderList = async () => {
    console.time('list time')
    const list = await getList()
    console.log(list)
    const total = list.length
    const page = 0
    const limit = 200
    const totalPage = Math.ceil(total / limit)
    const render = (page) => {
        if (page >= totalPage) return
        // Use requestAnimationFrame instead of setTimeout
        requestAnimationFrame(() => {
            for (let i = page * limit; i < page * limit + limit; i++) {
                const item = list[i]
                const div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                container.appendChild(div)
            }
            render(page + 1)
        }, 0)
    }
    render(page)
    console.timeEnd('list time')
}

Document fragments + requestAnimationFrame

Benefits of Document Fragmentation

1. Previously, appendChild was called every time a div tag was created. However, with document fragments, div tags of one page can be put into the document fragments first, and then appendChild to container at one time. This reduces the number of appendChild calls and greatly improves performance.

2. The page will only render the elements wrapped by the document fragment, but not the document fragment

const renderList = async () => {
    console.time('list time')
    const list = await getList()
    console.log(list)
    const total = list.length
    const page = 0
    const limit = 200
    const totalPage = Math.ceil(total / limit) 
    const render = (page) => {
        if (page >= totalPage) return
        requestAnimationFrame(() => {
            // Create a document fragment const fragment = document.createDocumentFragment()
            for (let i = page * limit; i < page * limit + limit; i++) {
                const item = list[i]
                const div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                // First insert the document fragment fragment.appendChild(div)
            }
            // One-time appendChild
            container.appendChild(fragment)
            render(page + 1)
        }, 0)
    }
    render(page)
    console.timeEnd('list time')
}

Lazy Loading

For a more popular explanation, let's start a vue front-end project, and the back-end service is still open.

In fact, the implementation principle is very simple. Let's show it through a picture. Put an empty node blank at the end of the list, then render the first page of data first, scroll up, and wait until blank appears in the view, which means the end. Then load the second page, and so on.

As for how to determine whether blank appears on the view, you can use getBoundingClientRect method to get top attribute

<script setup lang="ts">
import { onMounted, ref, computed } from 'vue'
const getList = () => {
  //Same code as above}
const container = ref<HTMLElement>() // container node const blank = ref<HTMLElement>() // blank node const list = ref<any>([]) // list const page = ref(1) // current page number const limit = 200 // one page display // maximum number of pages const maxPage = computed(() => Math.ceil(list.value.length / limit))
// The actual displayed list const showList = computed(() => list.value.slice(0, page.value * limit))
const handleScroll = () => {
  // Comparison of current page number and maximum page number if (page.value > maxPage.value) return
  const clientHeight = container.value?.clientHeight
  const blankTop = blank.value?.getBoundingClientRect().top
  if (clientHeight === blankTop) {
    // Blank appears in the view, the current page number increases by 1
    page.value++
  }
} 
onMounted(async () => {
  const res = await getList()
  list.value = res
})
</script> 
<template>
  <div class="container" @scroll="handleScroll" ref="container">
    <div class="sunshine" v-for="(item) in showList" :key="item.tid">
      <img :src="item.src" />
      <span>{{ item.text }}</span>
    </div>
    <div ref="blank"></div>
  </div>
</template>

The above is the details of how the front-end can better display the 100,000 pieces of data returned by the back-end. For more information about the front-end display of the 100,000 pieces of data returned by the back-end, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • How to display tens of thousands of data at one time with JavaScript
  • js front-end display and processing methods for large amounts of data
  • Java realizes the display of background data on the front end
  • Summary of methods for implementing front-end and back-end data interaction

<<:  Element with selection table to change the check box in the header into text implementation code

>>:  Summary of Textarea line break issues in HTML

Recommend

CSS3 realizes the red envelope shaking effect

There is a requirement to realize the shaking eff...

isPrototypeOf Function in JavaScript

Table of contents 1. isPrototypeOf() Example 1, O...

mysql method to recursively search for all child nodes of a menu node

background There is a requirement in the project ...

How to use Nginx to solve front-end cross-domain problems

Preface When developing static pages, such as Vue...

Optimize MySQL with 3 simple tweaks

I don't expect to be an expert DBA, but when ...

Detailed explanation of JavaScript object conversion to primitive value

Table of contents Object.prototype.valueOf() Obje...

A brief discussion on the Linux kernel's support for floating-point operations

Currently, most CPUs support floating-point units...

How to unify the character set on an existing mysql database

Preface In the database, some data tables and dat...

How to set up URL link in Nginx server

For websites with an architecture like LNMP, they...

How to analyze MySQL query performance

Table of contents Slow query basics: optimizing d...

Introduction to using the MySQL mysqladmin client

Table of contents 1. Check the status of the serv...

WeChat applet calculator example

WeChat applet calculator example, for your refere...

MySql quick insert tens of millions of large data examples

In the field of data analysis, database is our go...