core web vitals performance 太低

cls 太多:

因為很多圖片在沒載入時他在網頁上會沒有占空間,導致加載圖片後會大幅度影響到網頁版面配置,後來我將圖片容器設置固定大小來讓版面固定

LCP 載入時間太久,解決這個問題很棘手,在使用lighthouse分析web vitals之後,我得知LCP time的組成以及他的bottle neck在哪裡

total:

Phase % of LCP Timing
TTFB 10% 460 ms
Load Delay 55% 2,460 ms
Load Time 30% 1,340 ms
Render Delay 5% 240 ms
LCP time 100% 4500ms

分析工具提供了這些數據,還告訴我LCP是哪個元件,可以看到其中load Delay佔了最大一部分,我的case來說是heroSlide中的一張圖片,而這張圖片的url需要透過request 後端server拿到movie data之後才會拿到,可想而知可能就是這個環節最花時間因為要等待伺服器回傳圖片url才能進行後面的渲染,而我的問題其實滿簡單

useEffect(() => {
    const getMedias = async () => {
      const { response, err } = await mediaApi.getList({
        mediaType,
        mediaCategory,
        page: 1,
      })
      dispatch(setGlobalLoading(false))
      if (response) {
        setMovies(response.results)
        setLoopEnabled(response.results.length > 1)
      }
      if (err) toast.error(err.errors)
    }

    const getGenres = async () => {
      dispatch(setGlobalLoading(true))
      const { response, err } = await genreApi.getList({ mediaType })
      // console.log(response.genres)
      if (response) {
        setGenres(response.genres)
        getMedias()
      }
      if (err) {
        toast.error(err.errors)
        setGlobalLoading(false)
      }
    }

    getGenres()
  }, [mediaType, mediaCategory, dispatch])

可以看到一個很大的問題是明明呼叫movie API的參數中不需要Genres的response data,為什麼還需要等待gernes執行完呢,對沒錯所以我馬上想到我應該要同時呼叫這兩個api

useEffect(() => {
    const fetchData = async () => {
      dispatch(setGlobalLoading(true))

      const [genreResponse, mediaResponse] = await Promise.all([
        genreApi.getList({ mediaType }),
        mediaApi.getList({ mediaType, mediaCategory, page: 1 }),
      ])

      dispatch(setGlobalLoading(false))

      if (genreResponse.response) {
        setGenres(genreResponse.response.genres)
      } else {
        toast.error(genreResponse.err.errors)
      }

      if (mediaResponse.response) {
        setMovies(mediaResponse.response.results)
        setLoopEnabled(mediaResponse.response.results.length > 1)
      } else {
        toast.error(mediaResponse.err.errors)
      }
    }

    fetchData()
  }, [mediaType, mediaCategory, dispatch])

在使用Promise.all方法之後,我開心地想著應該會減少LCP時間吧,可是

Phase % of LCP Timing
TTFB 7% 320 ms
Load Delay 46% 2,060 ms
Load Time 43% 1,930 ms
Render Delay 4% 190 ms
LCP time 100% 4500ms

後來發現是我沒有把他build起來難怪performance很低

Header 設定

import axios from 'axios';

const get = async url => {
  const response = await axios.get(url, {
    headers: {
      Accept: 'application/json',        // 指定接受 JSON 格式的響應數據
      'Accept-Encoding': 'identity',    // 禁止響應數據壓縮
    },
  });
  return response.data;  // 返回響應中的數據部分
};

export default { get };