preface
Hello, I'm Lin Sanxin. In the most popular words, the most difficult knowledge point is my motto. The foundation is advanced, and the premise is my initial intention. Today, I'll talk to you. If the back end really returns 100000 data to the front end, how can we show it gracefully in the front end? (haha, assuming that the back end can really transmit 100000 data to the front end)
Front work
Do the pre work well before testing
Back end construction
Create a new server.js file, simply start a service, return 10w pieces of data to the front end, and start the service through nodemon server.js
Students who have not installed nodemon can install npm i nodemon -g globally first
// server.js const http = require('http') const port = 8000; http.createServer(function (req, res) { // Turn on Cors res.writeHead(200, { //Set the domain name that allows cross domain, or * allow all domain names 'Access-Control-Allow-Origin': '*', //Cross domain allowed request methods, or 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 100000 data 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 ${num}No. jiabinlin three heart`, tid: num }) } res.end(JSON.stringify(list)); }).listen(port, function () { console.log('server is listening on port ' + port); })
Front 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 to encapsulate an AJAX function to request the 10w data
// index.js // Request function const getList = () => { return new Promise((resolve, reject) => { //Step 1: create an asynchronous object var ajax = new XMLHttpRequest(); //Step 2: set the url parameters of the request. The first parameter is the type of the request, and the second parameter is the url of the request, which can take parameters ajax.open('get', 'http://127.0.0.1:8000'); //Step 3: send request ajax.send(); //Step 4: the registration event onreadystatechange will be called when the state changes ajax.onreadystatechange = function () { if (ajax.readyState == 4 && ajax.status == 200) { //Step 5: if you can enter this judgment, the data has come back perfectly, and the requested page exists resolve(JSON.parse(ajax.responseText)) } } }) } // Get container object const container = document.getElementById('container')
Direct Render
The most direct way is to render directly, but this is certainly not advisable, because rendering 10w nodes at one time is very time-consuming. Let's take a look at the time-consuming. It takes almost 12 seconds, 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 the limit of the number of pages per page, and then use setTimeout to render 1 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 rearrangements and greatly improves the performance. It is recommended that you use requestAnimationFrame more 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 fragment + requestAnimationFrame
Benefits of document fragmentation
- 1. In the past, every time a div tag was created, it was appendChild. However, with document fragments, you can first put the div tag of one page into the document fragment, and then appendChild into the container at one time, which reduces the number of appendChild and greatly improves the performance
- 2. The page renders only the elements wrapped in document fragments, not document fragments
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>` // Insert the document fragment first fragment.appendChild(div) } // Disposable 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 on
In fact, the implementation principle is very simple. Let's show it through a figure, that is, put an empty node blank at the end of the list, render the data on page 1 first, scroll up, and wait until blank appears in the view to explain the end. At this time, load the second page and push it later.
As for how to judge whether blank appears on the view, you can use the getBoundingClientRect method to obtain the 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 number of pages const limit = 200 // One page display // Maximum pages const maxPage = computed(() => Math.ceil(list.value.length / limit)) // Real show list const showList = computed(() => list.value.slice(0, page.value * limit)) const handleScroll = () => { // Comparison of current and maximum pages if (page.value > maxPage.value) return const clientHeight = container.value?.clientHeight const blankTop = blank.value?.getBoundingClientRect().top if (clientHeight === blankTop) { // If blank appears in the view, the current number of pages is increased 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>
Virtual list
There are a lot of virtual lists to explain. Here I share my article on virtual lists. Haha, I think it's good
In combination with the "Kangxi draft", let's talk about "virtual list"
epilogue
If you think this article is of little help to you, give a praise and encourage Lin Sanxin, ha ha. Or you can join my fishing group. If you want to join the learning group, please click here loaf on a job , I will regularly broadcast simulated interviews, resume guidance, and answer questions