Rumah > hujung hadapan web > tutorial js > Seni Smooth UX : Debouncing dan Throttling untuk UI yang lebih berprestasi

Seni Smooth UX : Debouncing dan Throttling untuk UI yang lebih berprestasi

DDD
Lepaskan: 2025-01-01 02:05:09
asal
898 orang telah melayarinya

Repositori Kod Github

Dalam dunia yang serba pantas, kebanyakan pekerjaan yang kami lakukan adalah di Web dan pantas. Mewujudkan pengalaman pengguna yang lancar dan lancar menjadi lebih penting. Pengguna menyukai UI yang berfungsi dengan pantas, tanpa ketinggalan atau kelewatan. Mencapai pengalaman yang hampir sempurna adalah mungkin, walaupun sukar. Pernahkah anda mendengar tentang Gelung Acara?

Dalam JavaScript, Gelung Acara ialah konsep asas yang mengurus susunan pelaksanaan kod, mengumpul proses, meletakkan arahan dalam sub-tugas beratur dan menjalankan operasi tak segerak dengan cekap. Berikut ialah pecahan pantas tentang cara gelung acara berfungsi:

  • Timbunan panggilan: Semua fungsi, apabila dipanggil, ditambahkan pada timbunan ini dan aliran kawalan kembali daripada fungsi, ia muncul daripada timbunan
  • Timbunan: Semua pembolehubah dan objek diperuntukkan memori daripada timbunan ini
  • Baris gilir: Senarai mesej/ arahan - yang dilaksanakan satu demi satu

Gelung acara ini menyemak tindanan panggilan secara berterusan. Pelaksanaan kod JavaScript diteruskan sehingga timbunan panggilan kosong.

Pengendalian acara ialah bahagian yang sangat penting dalam membina aplikasi JavaScript. Dalam aplikasi sedemikian, kami mungkin perlu mengaitkan berbilang acara dengan komponen UI.

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

Bayangkan...

Anda mempunyai Butang dalam UI yang membantu mengisi jadual dengan berita terkini dalam Sukan. Sekarang ini memerlukan anda untuk:

  • Klik Butang (Kaitkan pengendali acara "klik" dengan butang.
  • Ambil hasil daripada API
  • Menghuraikan output (Json) dan memaparkan

3 proses ini dirantai bersama secara serentak. Sekarang menekan Butang berulang kali bermakna berbilang panggilan API - mengakibatkan UI disekat selama beberapa saat - Pengalaman Pengguna yang kelihatan lambat.

Ini ialah kes penggunaan yang baik untuk pendekatan seperti Debouncing dan Throttling. Untuk acara seperti ini, yang mencetuskan rangkaian peristiwa yang kompleks - kita boleh menggunakan gerakan sedemikian untuk mengehadkan bilangan kali kita memanggil API, atau dalam pengertian umum - mengehadkan kadar di mana kita memproses acara.

Apakah itu Debouncing Versus throttling?

Menyahlantun: Menangguhkan pelaksanaan fungsi sehingga tempoh bertenang yang ditentukan telah berlalu sejak acara terakhir.

Contohnya:

Jika kami menyahlantunkan handleOnPressKey() selama 2 saat, ia akan dilaksanakan hanya jika pengguna berhenti menekan kekunci selama 2 saat.

Senario:

  • Tekan kekunci awal: Mulakan pemasa 2000ms untuk memanggil handleOnPressKey().
  • Tekanan kekunci seterusnya dalam masa 1000ms: Pemasa ditetapkan semula; kami menunggu 2000ms lagi dari penekan kekunci terbaru ini.
  • Tiada tekan kekunci untuk 2000ms: Pemasa selesai, dan handleOnPressKey() dipanggil.

Coretan Kod:

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);
Salin selepas log masuk
Salin selepas log masuk

Pendikit: Memastikan fungsi dipanggil paling banyak sekali dalam tempoh masa yang ditentukan, tidak kira berapa kerap peristiwa itu berlaku.

Contohnya:

Jika kita mendikit handleOnScroll() dengan selang 2 saat, fungsi akan dilaksanakan paling banyak sekali setiap 2 saat, walaupun acara tatal mencetuskan beberapa kali dalam tempoh itu.

Senario:

  • Acara tatal awal: handleOnScroll() dipanggil dan tempoh bertenang 2000ms bermula.
  • Acara tatal seterusnya dalam masa 2000ms: Ini diabaikan kerana tempoh bertenang aktif.
  • Acara tatal selepas 2000ms: handleOnScroll() dipanggil semula.

Contoh Kod:

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);
Salin selepas log masuk
Salin selepas log masuk

Sekarang Mari Bina sesuatu

Projek ini ialah aplikasi Senarai Tugasan moden yang direka untuk meneroka konsep menyahlantun dan mendikit dalam pengendalian acara. Ia menampilkan penambahan tugas masa nyata, fungsi carian yang dikuasakan oleh Fuse.js dan menu lungsur untuk cadangan dinamik.

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

Mari kita lihat kod HTML dengan cepat sebelum beralih pada skrip yang lebih kritikal.js

Kami telah menggunakan TailwindCSS untuk penggayaan pantas. Anda boleh menyemak dokumentasi mereka di sini Dokumentasi Tailwind - ia sangat membantu untuk membuat prototaip pantas

  • Pengepala: Pengepala mengandungi tajuk halaman.
  • Medan Input: Medan input untuk menambah nota, digayakan dengan CSS Tailwind.
  • Turun Turun untuk Cadangan: Turun turun tersembunyi yang akan memaparkan cadangan semasa menaip pengguna.
  • Senarai Tugas Statik: Senarai untuk memaparkan tugasan yang ditambah.
  • Skrip: Termasuk pustaka Fuse.js untuk carian kabur dan fail script.js untuk logik JavaScript tersuai.
<!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;
Salin selepas log masuk
Salin selepas log masuk

Bahagian ini memulakan pelbagai tugas dan mengisytiharkan pembolehubah untuk Fuse.js, pemasa nyahlantun dan pemasa pendikit. Kami telah mengekodkan beberapa tugasan - demi projek ini

Sekarang mari kita bina fungsi onSubmit. Fungsi ini akan dicetuskan sebaik sahaja pengguna mengklik pada Anak panah Hantar. Ia menghalang penyerahan borang lalai, mendapatkan semula nilai input, mengosongkan medan input, menambah tugas baharu pada tatasusunan tugas dan mengemas kini senarai tugas.

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);
Salin selepas log masuk
Salin selepas log masuk

Sekarang kita perlu memastikan bahawa sebaik sahaja tugasan diserahkan, tugas itu dikemas kini dalam senarai Tugas

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);
Salin selepas log masuk
Salin selepas log masuk

Fungsi updateList() memaparkan senarai tugas dengan menggelung melalui tatasusunan tugas dan mencipta item senarai untuk setiap tugas. Setiap item senarai termasuk titik tumpu dan teks tugasan.

Sekarang kita perlu memastikan bahawa senarai mendapat kemas kini selepas Halaman dimuatkan, kali pertama. Kami juga ingin memulakan Fuse.js pada beban Halaman - dan mengaitkan tatasusunan tugas dengannya. Ingat, kami ingin memberikan cadangan daripada tatasusunan tugas ini dalam menu lungsur.

<!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;
Salin selepas log masuk
Salin selepas log masuk
const onSubmit = (event) => {
    //Prevent default
    event.preventDefault();

    const text = document.getElementById("input").value.trim();
    document.getElementById("input").value = "";
    tasks.push(text);
    updateList();
}
Salin selepas log masuk

Sekarang kita perlu memastikan bahawa pada setiap 'input' kita mencari melalui senarai untuk menunjukkan cadangan dalam menu lungsur. Ini mempunyai 3 bahagian:

  • Tulis Logik Carian: searchTasks()
  • Isi dropdown pada setiap input: updateDropdown()
  • Kaitkan updateDropdown() untuk dipanggil pada setiap input (Sekurang-kurangnya buat masa ini :-) -> Sehingga kami melaksanakan logik nyahlantun/ pendikit)
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);
    })
}
Salin selepas log masuk
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);
    }
}
Salin selepas log masuk
document.addEventListener("DOMContentLoaded", init);
Salin selepas log masuk

Setakat ini: Senarai lungsur akan dikemas kini setiap kali anda menaip sesuatu - dalam UI yang lebih besar, kami tidak mahu pengalaman ini

Mengemas kini senarai lungsur pada setiap ketukan kekunci dalam UI yang besar boleh membawa kepada isu prestasi, menyebabkan ketinggalan dan pengalaman pengguna yang lemah. Kemas kini yang kerap boleh mengatasi gelung acara, yang membawa kepada kelewatan dalam memproses tugas lain.

Kini kita akan melihat cara kita boleh menggunakan Debouncing OR throttling untuk membantu mengurus kekerapan kemas kini, memastikan prestasi yang lebih lancar dan antara muka yang lebih responsif.

Begini cara kami boleh melaksanakan salah satu teknik dalam projek membuat nota kami.

Menyahlantun:

Menyahlantun memastikan bahawa fungsi hanya dipanggil selepas tempoh masa tertentu telah berlalu sejak seruan terakhir. Ini berguna untuk senario seperti medan input carian, di mana kami mahu menunggu pengguna selesai menaip sebelum membuat panggilan API.

Coretan Kod:

//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);
}
Salin selepas log masuk

Penjelasan:

  • Pendengar acara input dilampirkan pada medan input.
  • Fungsi clearTimeout memadam sebarang pemasa nyahpantun sedia ada.
  • Fungsi setTimeout menetapkan pemasa nyahpantun baharu selama 1 saat. Jika tiada input dikesan dalam tempoh ini, fungsi searchTasks dipanggil dengan nilai input.

Pendikit (Dalam kes penggunaan yang sama) - Gunakan salah satu daripada dua pendekatan

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";
}
Salin selepas log masuk

Penjelasan:

  • let lastCall = 0;: Memulakan pembolehubah untuk menjejaki kali terakhir searchTasks dipanggil.
  • document.getElementById("input").addEventListener("input", (event) => { ... });: Melampirkan pendengar acara input pada medan input.
  • const now = Date.now();: Mendapat masa semasa dalam milisaat.
  • kelewatan const = 1000;: Tetapkan kelewatan pendikit kepada 1 saat.
  • if (now - lastCall >= delay) { ... }: Menyemak sama ada cukup masa telah berlalu sejak panggilan terakhir.
    • const query = event.target.value.trim();: Mendapatkan semula nilai input yang dipangkas.
    • searchTasks(query);: Memanggil fungsi searchTasks dengan nilai input.
    • lastCall = now;: Mengemas kini masa lastCall kepada masa semasa.

Walau bagaimanapun, sila ambil perhatian: Pendikitan tidak sesuai untuk senario ini kerana ia mengehadkan kekerapan pelaksanaan fungsi kepada selang tetap, yang mungkin tidak memberikan pengalaman pengguna terbaik untuk cadangan carian masa nyata. Pengguna mengharapkan maklum balas segera semasa mereka menaip, dan pendikitan boleh menyebabkan kelewatan yang ketara.

Kes Penggunaan yang Lebih Baik untuk Pendikit

Pendikit lebih sesuai untuk senario di mana anda ingin mengawal kadar pengendalian acara untuk mengelakkan isu prestasi. Berikut ialah beberapa contoh:

  • Saiz Semula Tetingkap: Apabila pengguna mengubah saiz tetingkap penyemak imbas, anda mungkin mahu mengemas kini reka letak atau melakukan pengiraan. Pendikitan memastikan kemas kini ini berlaku pada kadar terkawal, menghalang panggilan fungsi yang berlebihan.
  • Menatal: Apabila mengendalikan acara tatal, seperti memuatkan lebih banyak kandungan atau mengemas kini UI berdasarkan kedudukan tatal, pendikitan membantu mengurus kekerapan kemas kini, memastikan prestasi lancar.
  • Penghadan Kadar API: Apabila membuat panggilan API, pendikitan boleh membantu anda kekal dalam had kadar dengan mengawal kekerapan permintaan.

Dengan menggunakan pendikitan dalam senario ini, anda boleh meningkatkan prestasi dan memastikan pengalaman pengguna yang lebih lancar.

Cari Kod Lengkap di sini

Selamat Pengekodan!


Sila tinggalkan maklum balas!

Saya harap anda mendapati blog ini membantu! Maklum balas anda sangat berharga bagi saya, jadi sila tinggalkan pendapat dan cadangan anda dalam komen di bawah.

Jangan ragu untuk berhubung dengan saya di LinkedIn untuk mendapatkan lebih banyak cerapan dan kemas kini. Mari kekal berhubung dan terus belajar dan berkembang bersama!

Atas ialah kandungan terperinci Seni Smooth UX : Debouncing dan Throttling untuk UI yang lebih berprestasi. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan