Try   HackMD
tags: Performance Patterns

Import on Visibility

前言

  • 常常有些components在初始時看不到,像是lazy loading images(圖片延遲載入)、無限滾動(infinite scrolling), 他在網頁初始的一開始看不到, 只有在使用者滑到網頁底部的時候才會get loaded. vedio
  • 我們不需要在網頁初始時 request 所有圖片, 這樣可以減少一開始的 loading time, 我們也可以對 components 做同樣的事

可使用 js API or libraries

IntersectionObserver

  • callback 函式:當目標元素進入或離開指定外層或預設 viewport 時觸發
  • options:設定在哪些情況下觸發callback 函式
// entries 能拿到所有目標元素進出(intersect)變化的資訊 let callback = (entries, observer) => { // 取得每一個 entry 都是描述被觀察物件有 intersection change 的情況, 做一些處理或工作 entries.forEach(entry => { entry.target entry.isIntersecting entry.intersectionRatio // 被觀察者(target)和觀察者(viewport)的重疊比例 // entry.boundingClientRect // entry.intersectionRect // entry.rootBounds // entry.time }); }; let options = { root: document.querySelector('#scrollArea'), // 預設 document viewport rootMargin: '0px', // 預設 0, 也可以設定 '10px 20px 30px 40px' threshold: 1.0 // 預設 0, 也可以使用陣列 [0, 0.25, 0.5, 0.75, 1] } // 製作鈴鐺:建立一個 intersection observer,帶入相關設定資訊 let observer = new IntersectionObserver(callback, options); // 設定觀察對象:告訴 observer 要觀察哪個目標元素 observer.observe(TARGET_ELEMENT) }
  • root 必須要是所有目標元素的父元素(或祖父層的元素)
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  • rootMargin:設定 root 周圍的 margin — 能有效的擴大或縮小這個用來觀察的盒子範圍。設定的值就類似設定一般 margin:"30px 30px 30px 30px"(上右下左),也能縮寫成一個值:30px
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  • threshold:設定目標元素的可見度達到多少比例時,觸發 callback 函式。可以帶入單一一個值:只想在可見度達一個比例時觸發;也可帶入一個陣列:想在可見度達多個比例時觸發
    • 預設值為 0:一但目標進入或目標的最後一個 px 離開觀察範圍時就觸發
    • 設定為 0.5 :一但可見度為 50% 時就觸發
    • 設定為 [0, 0.25, 0.5, 0.75, 1]:可見度每跳 25% 時就觸發
    • 設定為 1:可見度達 100% 或一但往下掉低於 100% 時就觸發

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • entry.target: 取得是哪個目標元素進入或離開了 viewport
  • isIntersecting:用來判別目標元素是否進入或離開了 viewport
    • 值由 false 轉為 true:目標元素進入 viewport
    • 值由 true 轉為 false:目標元素離開 viewport
let callback = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { // 只在目標元素進入 viewport 時執行這裡的工作 } else { // 只在目標元素離開 viewport 時執行這裡的工作 } }) }
  • rootBounds: 用來觀察的盒子 (root + rootMargin)
  • boundingClientRect: 目標元素
  • intersectionRect: 目標元素和盒子重疊的區塊

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • intersectionRatio:目標元素有多少比例和用來觀察的盒子重疊(白話的來說:目標元素的可見度為多少)。計算方式:intersectionRect / boundingClientRect

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
threshold 與 intersectionRatio 兩者差異 ?

  • threshold 當中所設定的單一或多個值就是在設定一個個 intersectionRatio 值作為門檻,一但跨越這個門檻(或這些門檻),就觸發 callback 函式
  • options 所設定的 threshold 是想訂定「何時觸發」;intersectionRatio 則是當目標元素進出(intersect)變化當下的即時資訊

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • observer.unobserve(entry.target): 只想一次性偵測目標對象的進入或離開
let callback = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { // 目標元素進入 viewport 時做一些事情 ... // 完成後,結束觀察 observer.unobserve(entry.target) } }) }

demo

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Jun 1, 2022 除了IE不支援, chrome, safari, firefox都支援
Can I use Search?

React libraries

  • react-lazyload demo
  • react-loadable-visibility, 當使用者點擊時import component 原始demo

優點

  • 優化 performance, 減少一開始的loading time, 在需要 images 或 component 再載入與使用者多一些互動, 甚至讓使用者知道程式並未凍結像是點擊後 Emoji table 再出現, 當使用者點擊 icon 時需要等一下 (short time) 程式會 loaded, parsed, compiled, and executed module ! vedio

Reference

Intersection Observer API MDN
Intersection Observer API:Lazy Loading, Infinite Scroll
dynamic import HackMD
modules-dynamic-imports article