Como a otimização do desempenho de front-end renderiza grandes quantidades de dados na página

Site recomendado LuckyCola para ferramentas front-end essenciais (cama de imagens grátis, API, chatAI, etc.):
https://luckycola.com.cn/

1. Fundo

A maior parte da interação de dados entre front-end e back-end ocorre na forma de interfaces. Às vezes, a quantidade de dados retornados pelo back-end para o front-end é muito grande, e o front-end precisa renderizar esses dados à visualização da página de acordo com as necessidades do negócio, então a quantidade de dados é enorme. Nesse caso, esse consumo de desempenho de front-end também é enorme, então como podemos lidar com essa situação de forma mais eficiente?

2. Introdução ao programa

1. Renderização direta

A maneira mais direta é renderizar todos os dados na página de uma vez. código mostrado abaixo:

const renderList = async () => {
    
    
    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)
    })
}
renderList()

A renderização de 100.000 registros por vez leva cerca de 12 segundos, o que obviamente não é aconselhável.

2. Renderização de paginação por meio de setTimeout

Um método de otimização simples é paginar os dados. Supondo que cada página possua um registro de limite, os dados podem ser divididos em páginas Math.ceil (total/limite). Depois, podemos usar setTimeout para renderizar as páginas sequencialmente, uma página por vez.

const renderList = async () => {
    
    

    const list = await getList()

    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)
}

Após a paginação, os dados podem ser rapidamente renderizados na tela, reduzindo o tempo de página em branco.

3. Renderização de paginação por meio de requestAnimationFrame

Ao renderizar a página, podemos usar requestAnimationFrame em vez de setTimeout, o que pode reduzir o número de refluxos e melhorar o desempenho.

const renderList = async () => {
    
    
    const list = await getList()

    const total = list.length
    const page = 0
    const limit = 200
    const totalPage = Math.ceil(total / limit)

    const render = (page) => {
    
    
        if (page >= totalPage) return

        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)
        })
    }
    render(page)
}

O método window.requestAnimationFrame() informa ao navegador que você deseja executar a animação e solicita que o navegador chame a função especificada para atualizar a animação antes do próximo redesenho. Este método toma o retorno de chamada como parâmetro a ser chamado antes de redesenhar.

4. Fragmentos de documentos

Anteriormente, toda vez que um elemento div era criado, o elemento era inserido diretamente na página via appendChild. MasappendChild é uma operação cara.
Na verdade, podemos primeiro criar um fragmento de documento, criar o elemento div e depois inserir o elemento no fragmento de documento. Depois que todos os elementos div forem criados, insira o fragmento na página. Fazer isso também pode melhorar o desempenho da página.


const renderList = async () => {
    
    
    console.time('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(() => {
    
    

            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>`

                fragment.appendChild(div)
            }
            container.appendChild(fragment)
            render(page + 1)
        })
    }
    render(page)
    console.timeEnd('time')
}

5. Carregamento lento

Embora o back-end retorne muitos dados de uma vez, a tela do usuário só pode exibir dados limitados ao mesmo tempo. Portanto, podemos usar uma estratégia de carregamento lento para renderizar dados dinamicamente com base na posição de rolagem do usuário.
Para obter a posição de rolagem do usuário, podemos adicionar um nó vazio no final da lista. Sempre que a janela de visualização fica em branco, significa que o usuário rolou até o final da página da web, o que significa que precisamos continuar renderizando os dados.
Ao mesmo tempo, podemos usar getBoundingClientRect para determinar se o espaço em branco está na parte inferior da página.


<script setup lang="ts">
import {
    
     onMounted, ref, computed } from 'vue'
const getList = () => {
    
    
  // code as before
}
const container = ref<HTMLElement>() // container element
const blank = ref<HTMLElement>() // blank element
const list = ref<any>([])
const page = ref(1)
const limit = 200
const maxPage = computed(() => Math.ceil(list.value.length / limit))
// List of real presentations
const showList = computed(() => list.value.slice(0, page.value * limit))
const handleScroll = () => {
    
    
  if (page.value > maxPage.value) return
  const clientHeight = container.value?.clientHeight
  const blankTop = blank.value?.getBoundingClientRect().top
  if (clientHeight === blankTop) {
    
    
    // When the blank node appears in the viewport, the current page number is incremented by 1
    page.value++
  }
}
onMounted(async () => {
    
    
  const res = await getList()
  list.value = res
})
</script>

<template>
  <div id="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>

Acho que você gosta

Origin blog.csdn.net/qq_48896417/article/details/131266808
Recomendado
Clasificación