> 웹 프론트엔드 > JS 튜토리얼 > Smooth UX의 기술: 보다 성능이 뛰어난 UI를 위한 디바운싱 및 조절

Smooth UX의 기술: 보다 성능이 뛰어난 UI를 위한 디바운싱 및 조절

DDD
풀어 주다: 2025-01-01 02:05:09
원래의
897명이 탐색했습니다.

Github 코드 저장소

빠르게 변화하는 세상에서 우리가 하는 대부분의 작업은 웹에서 빠르게 이루어집니다. 원활하고 원활한 사용자 경험을 만드는 것이 더욱 중요해졌습니다. 소비자는 지연이나 지연 없이 빠르게 작동하는 UI를 좋아합니다. 비록 까다롭기는 하지만 거의 완벽한 경험을 달성하는 것은 가능합니다. 이벤트 루프(Event Loop)에 대해 들어보셨나요?

JavaScript에서 이벤트 루프는 코드 실행 순서를 관리하고, 프로세스를 수집하고, 대기열에 있는 하위 작업에 명령을 넣고, 비동기 작업을 효율적으로 실행하는 기본 개념입니다. 이벤트 루프 작동 방식에 대한 간략한 설명은 다음과 같습니다.

  • 호출 스택: 호출되면 모든 함수가 이 스택에 추가되고, 함수에서 제어 흐름이 반환되면 스택에서 팝됩니다.
  • 힙: 모든 변수와 객체는 이 힙에서 메모리를 할당받습니다
  • 큐: 차례로 실행되는 메시지/명령 목록

이 이벤트 루프는 호출 스택을 지속적으로 확인합니다. 호출 스택이 빌 때까지 JavaScript 코드 실행이 계속됩니다.

이벤트 처리는 JavaScript 애플리케이션 구축에 있어 매우 중요한 부분입니다. 이러한 애플리케이션에서는 여러 이벤트를 UI 구성 요소와 연결해야 할 수도 있습니다.

The art of Smooth UX : Debouncing and Throttling for a more performant UI

상상해 보세요...

UI에는 최신 스포츠 뉴스로 테이블을 채우는 데 도움이 되는 버튼이 있습니다. 이제 다음이 필요합니다.

  • 버튼 클릭("클릭" 이벤트 핸들러를 버튼과 연결합니다.
  • API에서 결과 가져오기
  • 출력(Json)을 구문 분석하고 표시

이 3가지 프로세스는 동기식으로 함께 연결됩니다. 이제 버튼을 반복적으로 누르면 여러 API 호출이 발생하여 UI가 몇 초 동안 차단되어 사용자 경험이 느려지는 것처럼 보입니다.

이는 디바운싱 및 제한과 같은 접근 방식에 대한 좋은 사용 사례입니다. 복잡한 이벤트 체인을 트리거하는 이와 같은 이벤트의 경우 이러한 조작을 사용하여 API를 호출하는 횟수를 제한하거나 일반적인 의미에서 이벤트를 처리하는 속도를 제한할 수 있습니다.

디바운싱과 조절이란 무엇입니까?

디바운싱: 마지막 이벤트 이후 지정된 대기 시간이 경과할 때까지 함수 실행을 연기합니다.

예:

2초 동안 handlerOnPressKey()를 디바운스하면 사용자가 2초 동안 키 누르기를 중지한 경우에만 실행됩니다.

대본:

  • 초기 키 누르기: 2000ms 타이머를 시작하여 handlerOnPressKey()를 호출합니다.
  • 1000ms 이내에 다음 키를 누르면: 타이머가 재설정됩니다. 이 최신 키 누르기로부터 2000ms를 더 기다립니다.
  • 2000ms 동안 키를 누르지 않음: 타이머가 완료되고 handlerOnPressKey()가 호출됩니다.

코드 조각:

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초 간격으로 handlerOnScroll()을 조절하면 해당 기간 내에 스크롤 이벤트가 여러 번 트리거되더라도 함수는 최대 2초마다 한 번씩 실행됩니다.

대본:

  • 초기 스크롤 이벤트: handlerOnScroll()이 호출되고 2000ms의 쿨다운이 시작됩니다.
  • 2000ms 내의 후속 스크롤 이벤트: 쿨다운 기간이 활성화되어 있으므로 무시됩니다.
  • 2000ms 후 스크롤 이벤트: handlerOnScroll()이 다시 호출됩니다.

코드 예:

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);
로그인 후 복사
로그인 후 복사

이제 뭔가를 만들어 봅시다

이 프로젝트는 이벤트 처리에서 디바운싱제한 개념을 탐구하도록 설계된 현대적인 To-Do List 애플리케이션입니다. 실시간 작업 추가, Fuse.js에서 제공하는 검색 기능, 동적 제안 드롭다운이 특징입니다.

The art of Smooth UX : Debouncing and Throttling for a more performant UI

더 중요한 script.js로 넘어가기 전에 HTML 코드를 빠르게 살펴보겠습니다

빠른 스타일링을 위해 TailwindCSS를 사용했습니다. 여기에서 해당 문서를 확인할 수 있습니다. Tailwind 문서 - 빠른 프로토타입을 만드는 데 큰 도움이 됩니다

  • 헤더: 헤더에는 페이지 제목이 포함됩니다.
  • 입력 필드: Tailwind CSS로 스타일이 지정된 메모 추가용 입력 필드입니다.
  • 제안사항 드롭다운: 사용자가 입력할 때 제안사항을 표시하는 숨겨진 드롭다운입니다.
  • 정적 작업 목록: 추가된 작업을 표시하는 목록입니다.
  • 스크립트: 퍼지 검색을 위한 Fuse.js 라이브러리와 사용자 정의 JavaScript 로직을 위한 script.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;
로그인 후 복사
로그인 후 복사

이 섹션에서는 작업 배열을 초기화하고 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();
}
로그인 후 복사

이제 모든 '입력'에 대해 목록을 검색하여 드롭다운에 제안 사항이 표시되도록 해야 합니다. 이는 세 부분으로 구성됩니다:

  • 검색 로직 작성: searchTasks()
  • 모든 입력에 대해 드롭다운 채우기: updateDropdown()
  • 모든 입력에서 호출되도록 updateDropdown()을 연결합니다(적어도 지금은 :-) -> 디바운싱/제한 논리를 구현할 때까지)
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);
}
로그인 후 복사

설명:

  • 입력 이벤트 리스너가 입력 필드에 연결됩니다.
  • clearTimeout 함수는 기존 디바운스 타이머를 모두 지웁니다.
  • setTimeout 함수는 새로운 디바운스 타이머를 1초로 설정합니다. 이 기간 내에 입력이 감지되지 않으면 입력 값으로 searchTasks 함수가 호출됩니다.

제한(동일한 사용 사례) - 두 가지 접근 방식 중 하나를 사용합니다.

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";
}
로그인 후 복사

설명:

  • let lastCall = 0;: searchTasks가 마지막으로 호출된 시간을 추적하기 위해 변수를 초기화합니다.
  • document.getElementById("input").addEventListener("input", (event) => { ... });: 입력 이벤트 리스너를 입력 필드에 연결합니다.
  • const now = Date.now();: 현재 시간을 밀리초 단위로 가져옵니다.
  • const Delay = 1000;: 스로틀 지연을 1초로 설정합니다.
  • if (now - lastCall >= Delay) { ... }: 마지막 호출 이후 충분한 시간이 지났는지 확인합니다.
    • const query = event.target.value.trim();: 잘린 입력 값을 검색합니다.
    • searchTasks(query);: 입력값으로 searchTasks 함수를 호출합니다.
    • lastCall = now;: lastCall 시간을 현재 시간으로 업데이트합니다.

그러나 참고: 조절은 함수 실행 빈도를 고정된 간격으로 제한하여 실시간 검색 제안에 대한 최상의 사용자 경험을 제공하지 못할 수 있으므로 이 시나리오에 가장 적합하지 않습니다. 사용자는 입력할 때 즉각적인 피드백을 기대하며 제한으로 인해 눈에 띄는 지연이 발생할 수 있습니다.

제한에 대한 더 나은 사용 사례

제한은 성능 문제를 방지하기 위해 이벤트 처리 속도를 제어하려는 시나리오에 더 적합합니다. 다음은 몇 가지 예입니다.

  • 창 크기 조정: 사용자가 브라우저 창의 크기를 조정하면 레이아웃을 업데이트하거나 계산을 수행할 수 있습니다. 조절은 이러한 업데이트가 제어된 속도로 발생하도록 보장하여 과도한 함수 호출을 방지합니다.
  • 스크롤링: 더 많은 콘텐츠를 로드하거나 스크롤 위치에 따라 UI를 업데이트하는 등 스크롤 이벤트를 처리할 때 조절을 사용하면 업데이트 빈도를 관리하여 원활한 성능을 보장할 수 있습니다.
  • API 속도 제한: API 호출 시 조절을 사용하면 요청 빈도를 제어하여 속도 제한 내에서 유지하는 데 도움이 될 수 있습니다.

이러한 시나리오에서 제한을 사용하면 성능을 향상하고 보다 원활한 사용자 경험을 보장할 수 있습니다.

여기에서 전체 코드를 찾으세요

즐거운 코딩하세요!


의견을 남겨주세요!

이 블로그가 도움이 되었기를 바랍니다! 여러분의 피드백은 저에게 매우 소중합니다. 아래 댓글에 여러분의 생각과 제안을 남겨주세요.

더 많은 통찰력과 업데이트를 원하시면 언제든지 LinkedIn에서 저와 연락해 주세요. 계속 연결되어 함께 배우고 성장해 나가세요!

위 내용은 Smooth UX의 기술: 보다 성능이 뛰어난 UI를 위한 디바운싱 및 조절의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿