Github 程式碼庫
在快節奏的世界中,我們所做的大部分工作都是在網路上完成的,而且速度很快。創造無縫、流暢的使用者體驗變得更加重要。消費者喜歡運行速度快、沒有延遲或延遲的使用者介面。實現近乎完美的體驗是可能的,儘管很棘手。您聽過事件循環嗎?
在 JavaScript 中,事件循環是一個基本概念,它管理程式碼的執行順序、收集進程、將指令放入排隊的子任務中並有效率地執行非同步操作。以下是事件循環運作原理的快速分解:
此事件循環不斷檢查呼叫堆疊。 JavaScript 程式碼的執行將繼續,直到呼叫堆疊為空。
事件處理是建立 JavaScript 應用程式的一個非常重要的部分。在這樣的應用程式中,我們可能需要將多個事件與 UI 元件相關聯。
UI 中有一個按鈕,可協助在表格中填入最新的體育新聞。現在這需要您:
這 3 個進程以同步方式連結在一起。現在,重複按下按鈕意味著多次 API 呼叫 - 導致 UI 被阻塞相當長的時間 - 看似滯後的用戶體驗。
這是 Debouncing 和 Throttling 等方法的一個很好的用例。對於此類觸發一系列複雜事件的事件 - 我們可以使用此類操作來限制呼叫 API 的次數,或者一般意義上 - 限制我們處理事件的速率。
去抖動:延遲函數的執行,直到上次事件以來經過指定的冷卻時間。
例如:
如果我們對handleOnPressKey()進行反跳2秒,則只有當使用者停止按鍵2秒時才會執行。
程式碼片段:
let debounceTimer; // Timer reference const handleOnPressKey = () => { console.log("Key pressed and debounce period elapsed!"); }; const debouncedKeyPress = () => { // Clear any existing timer clearTimeout(debounceTimer); // Start a new debounce timer debounceTimer = setTimeout(() => { handleOnPressKey(); // Execute the function after cooldown }, 2000); // Cooldown period of 2000ms }; // Attach debouncedKeyPress to keypress events document.getElementById("input").addEventListener("keypress", debouncedKeyPress);
限制:確保函數在指定時間段內最多呼叫一次,無論事件發生的頻率為何。
例如:
如果我們以2秒間隔限制handleOnScroll(),則函數最多每2秒執行一次,即使滾動事件在該時間段內觸發多次。
程式碼範例:
let throttleTimer; // Timer reference const handleOnScroll = () => { console.log("Scroll event processed!"); }; const throttledScroll = () => { if (!throttleTimer) { handleOnScroll(); // Execute the function immediately throttleTimer = setTimeout(() => { throttleTimer = null; // Reset timer after cooldown }, 2000); // Cooldown period of 2000ms } }; // Attach throttledScroll to scroll events document.addEventListener("scroll", throttledScroll);
讓我們快速看一下 HTML 程式碼,然後再進入更關鍵的 script.js
我們使用 TailwindCSS 來快速設計樣式。您可以在此處查看他們的文檔 Tailwind 文件 - 它對於製作快速原型非常有幫助
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Event Loop Practice</title> <!-- Tailwind CSS CDN --> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <style> /* Tailwind Extensions (Optional for Customizations) */ body { font-family: 'Inter', sans-serif; } </style> </head> <body> <h3> Why Use Fuse.js? </h3> <p>Fuse.js is a lightweight, customizable library for fuzzy searching. It handles typos and partial matches, offers high performance for large datasets, and has an intuitive API. This will help enhance your search functionality with flexible, user-friendly search experiences. Additionally, this provides you with a CDN link, so it can work right of the bat, no imports or local storage required.</p> <h2>Now let's Code in the Real Deal - The JS</h2> <h4> 1. Task Array and Variables </h4> <pre class="brush:php;toolbar:false">const tasks = new Array ( "Complete Blog on Throttling + Debouncing", "Make a list of 2025 Resolutions", ); let fuse = undefined; let debounceTimer; let throttleTimer;
本節初始化任務數組並宣告 Fuse.js、防抖計時器和節流計時器的變數。為了這個項目,我們已經硬編碼了一些任務
現在讓我們建立 onSubmit 函數。一旦使用者點擊“提交”箭頭,就會觸發此功能。它阻止預設表單提交,檢索輸入值,清除輸入字段,將新任務新增到任務數組,並更新任務清單。
let debounceTimer; // Timer reference const handleOnPressKey = () => { console.log("Key pressed and debounce period elapsed!"); }; const debouncedKeyPress = () => { // Clear any existing timer clearTimeout(debounceTimer); // Start a new debounce timer debounceTimer = setTimeout(() => { handleOnPressKey(); // Execute the function after cooldown }, 2000); // Cooldown period of 2000ms }; // Attach debouncedKeyPress to keypress events document.getElementById("input").addEventListener("keypress", debouncedKeyPress);
現在我們需要確保任務提交後,它會在任務清單中更新
let throttleTimer; // Timer reference const handleOnScroll = () => { console.log("Scroll event processed!"); }; const throttledScroll = () => { if (!throttleTimer) { handleOnScroll(); // Execute the function immediately throttleTimer = setTimeout(() => { throttleTimer = null; // Reset timer after cooldown }, 2000); // Cooldown period of 2000ms } }; // Attach throttledScroll to scroll events document.addEventListener("scroll", throttledScroll);
updateList() 函數透過循環遍歷任務數組並為每個任務建立清單項目來呈現任務清單。每個清單項目都包含一個項目符號點和任務文字。
現在我們需要確保清單在第一次載入頁面後得到更新。我們還希望在頁面載入時初始化 Fuse.js - 並將任務數組與其關聯。請記住,我們希望在下拉清單中呈現來自此任務陣列的建議。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Event Loop Practice</title> <!-- Tailwind CSS CDN --> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <style> /* Tailwind Extensions (Optional for Customizations) */ body { font-family: 'Inter', sans-serif; } </style> </head> <body> <h3> Why Use Fuse.js? </h3> <p>Fuse.js is a lightweight, customizable library for fuzzy searching. It handles typos and partial matches, offers high performance for large datasets, and has an intuitive API. This will help enhance your search functionality with flexible, user-friendly search experiences. Additionally, this provides you with a CDN link, so it can work right of the bat, no imports or local storage required.</p> <h2>Now let's Code in the Real Deal - The JS</h2> <h4> 1. Task Array and Variables </h4> <pre class="brush:php;toolbar:false">const tasks = new Array ( "Complete Blog on Throttling + Debouncing", "Make a list of 2025 Resolutions", ); let fuse = undefined; let debounceTimer; let throttleTimer;
const onSubmit = (event) => { //Prevent default event.preventDefault(); const text = document.getElementById("input").value.trim(); document.getElementById("input").value = ""; tasks.push(text); updateList(); }
現在我們需要確保在每個「輸入」中我們都會搜尋清單以在下拉清單中顯示建議。這有 3 個部分:
const updateList = () => { const lists = document.getElementById("taskList"); lists.innerHTML = ""; //Loop through all elements in tasks tasks.forEach(task => { const taskElement = document.createElement("li"); taskElement.classList.add("flex", "items-center", "space-x-2"); //Add Bullet Point Element const bullet = document.createElement("span"); bullet.classList.add("h-2", "w-2", "bg-blue-500", "rounded-full"); //Add Span Tag const taskText = document.createElement("span"); taskText.textContent = task; taskElement.appendChild(bullet); taskElement.appendChild(taskText); lists.appendChild(taskElement); }) }
const init = () => { console.log("Initializing..."); //Update and render the list updateList(); //Initialize Fuse with the updated array try{ fuse = new Fuse(tasks, { includeScore: true, threshold: 0.3 //For sensitivity }) } catch(e) { console.log("Error initializing Fuse:"+ fuse); } }
document.addEventListener("DOMContentLoaded", init);
到目前為止:每次您輸入內容時,下拉清單都會更新 - 在更龐大的 UI 中,我們不希望出現這種體驗
在龐大的 UI 中每次按鍵時更新下拉列表可能會導致效能問題,從而導致延遲和糟糕的用戶體驗。頻繁的更新可能會壓垮事件循環,導致處理其他任務的延遲。
我們現在將了解如何使用去抖動或節流來幫助管理更新頻率,確保更流暢的效能和更靈敏的介面。
以下是我們如何在筆記製作專案中實現這兩種技術的方法。
去抖動確保函數僅在自上次呼叫以來經過指定時間後才被呼叫。這對於搜尋輸入欄位等場景非常有用,在這些場景中我們希望等待使用者完成輸入後再進行 API 呼叫。
程式碼片段:
//Utility function to search within already entered values const searchTasks = (query) => { const result = fuse.search(query); const filteredTasks = result.map(result => result.item) updateDropdown(filteredTasks); }
說明:
const updateDropdown = (tasks) => { const dropdown = document.getElementById("dropdown"); dropdown.innerHTML = ""; if(tasks.length === 0) { dropdown.style.display = "none"; return; } tasks.forEach(task => { const listItem = document.createElement("li"); listItem.textContent = task; listItem.addEventListener("click", () => { document.getElementById("input").value = task; dropdown.style.display = "none"; }) dropdown.appendChild(listItem); }); dropdown.style.display = "block"; }
說明:
但是,請注意:限流並不是最適合這種場景,因為它將函數執行的頻率限制在固定的時間間隔內,這可能無法為即時搜尋建議提供最佳的使用者體驗。使用者期望在輸入時立即獲得回饋,而限制可能會導致明顯的延遲。
限流更適合您想要控制事件處理速率以避免效能問題的場景。以下是一些例子:
透過在這些場景中使用限制,您可以提高效能並確保更流暢的使用者體驗。
在此處找到完整程式碼
編碼快樂!
請留下回饋!
我希望您覺得這個部落格有幫助!您的回饋對我來說非常寶貴,所以請在下面的評論中留下您的想法和建議。
請隨時在 LinkedIn 上與我聯繫以獲取更多見解和更新。讓我們保持聯繫,繼續共同學習和成長!
以上是平滑使用者體驗的藝術:去抖動和節流以獲得更高效能的使用者介面的詳細內容。更多資訊請關注PHP中文網其他相關文章!