برنامه‌نویسی

پیاده‌سازی تابع Debounce ‌در زبان JavaScript

پیاده‌سازی تابع debounce در زبان javascript

اگر بخواهیم توابع debounce را شرح دهیم می‌توان گفت که آنها در دسته توابع higher-order قرار می‌گیرند و با استفاده از آنها می‌توانیم سرعت فراخوانی تابع دیگری را محدود کنیم، مثلا منتظر بمانیم تا تایپ کردن کاربر تمام شود و سپس نتایج را به او نشان دهیم.

توابع higher-order، تابعی را به عنوان ورودی دریافت یا تابعی را return می‌کنند، اما تابع debounce هر دو کار را انجام می‌دهد. یکی از معمول‌ترین استفاده‌ها از تابع debounce برای ارسال argument به event listener یک المنت HTML است. برای درک بهتر فایده و ساختار آن، به مثال زیر دقت داشته باشید.

جستجوی کلمه‌ی canada با استفاده از debounce

فرض کنید که شما تابعی با نام myFunc را در هر بار که چیزی در قسمت input تایپ می‌شود، فراخوانی می‌کنید اما بعد از مدتی تصمیم می‌گیرید که تجربه کاربری برنامه خود را تغییر دهید. مثلا می‌خواهید که تابع myFunc، دو ثانیه پس از تایپ آخرین کلمه اجرا شود. این همان جایی است که شما می‌توانید از تابع debounce استفاده کنید. بنابراین می‌بایست به‌جای تابع myFunc از تابع debounce خود در event listener استفاده کرده و سپس تابع myFunc را به عنوان یک ورودی به تابع debounce می‌دهید.

حال با استفاده از این تجربه کاربری جدید، تابع myFunc دو ثانیه پس از نوشتن آخرین کلمه در input اجرا می‌شود.

نحوه پیاده‌سازی تابع debounce

کدهای زیر همان ۷ خط کدی هستند که باید در پیاده‌سازی تابع debounce درک کنید.

function debounce( callback, delay ) {
    let timeout;
    return function() {
        clearTimeout( timeout );
        timeout = setTimeout( callback, delay );
    }
}

با خط اول شروع می‌کنیم، یک تابع با نام debounce ایجاد کرده‌ایم که دو ورودی با نام‌های callback و delay دریافت می‌کند.

function debounce( callback, delay ) {

}

callback همان تابعی است که می‌خواهیم تعداد دفعات اجرای آن را محدود کنیم وdelay که بر حسب میلی‌ثانیه محاسبه می‌شود همان زمانی است که باید قبل از اجرای مجدد تابع callback سپری شود.

function debounce( callback, delay ) {
    let timeout;
}

در خط دوم، یک متغیر با نام timeout تعریف می‌کنیم. این متغیر جدید مقدار timeoutID را که از فراخوانی setTimeout به‌دست می‌آید، در خود نگه می‌دارد.

function debounce( callback, delay ) {
    let timeout;
    return function() {
    }
}

در خط سوم، زیر متغیر timeout یک تابع anonymous را return می‌کنیم تا پس از اجرای تابع debounce بتوانیم به مقدار آن دسترسی داشته باشیم.

closure زمانی اتفاق می افتد که یک تابع به یک داده خارج از اسکوپ خود اشاره کند و بعد اگر آن تابع در جای دیگری مورد استفاده قرار گیرد، به دلیل خاصیت closure آن اسکوپ از بین نرفته و تابع در صورت نیاز به آن داده دسترسی خواهد داشت.

function debounce( callback, delay ) {
    let timeout;
    return function() {
        clearTimeout( timeout );
    }
}

در خط چهارم از متد clearTimeout که از mixin WindowOrWorkerGlobalScope نشعت گرفته، استفاده می‌کنیم. با این کار اطمینان حاصل می‌شود که هر بار تابع debounce اجرا می‌شود، مقدار timeout مجددا تنظیم شده و شمارش شروع می‌شود.

شما با استفاده ازWindowOrWorkerGlobalScope در زبان JavaScript می‌توانید به متدهای شناخته شده‌ای مانند setTimeout، clearTimeout، setInterval، clearInterval و fetch دسترسی داشته باشید.

function debounce( callback, delay ) {
    let timeout;
    return function() {
        clearTimeout( timeout );
        timeout = setTimeout( callback, delay );
    }
}

در خط پنجم به پایان پیاده‌سازی تابع debounce می‌رسیم. در این خط کد، چندین کار انجام می‌شود. اولین کار، اختصاص مقدار timeoutID با فراخوانی تابع setTimeout به متغیر timeout است که در خط دوم تعریف کرده بودیم. این کار به ما امکان می‌دهد که با فراخوانی تابع setTimeout یک reference به متغیر timeout بسازیم، بنابراین می‌توانیم مقدار timeout را در هر بار فراخوانی تابع debounce، مجددا تنظیم کنیم.

کار بعدی فراخوانی تابع setTimeout است و با استفاده از این تابع می‌توانید یک تاخیر در اجرای تابع callback ایجاد کنید.

از آنجا که ما از timeout استفاده می‌کنیم، تابع callback زمانی اجرا می‌شود که مقدار این متغیر به صفر برسد. به این صورت با هر بار فراخوانی تابع debounce، مقدار متغیر timeout مجددا به مقدار delay بازنشانی می‌شود و بدین صورت می‌توانیم اجرای تابع myFunc را محدود کنیم.

خط‌های ۶ و ۷ شامل براکت‌ها هستند که مطمئنا نیازی به توضیح ندارند.

تا اینجا متوجه شدید که عملکرد تابع debounce به چه شکل است، در ادامه با استفاده از توضیحات قبل، یک مثال واقعی از کارکرد این تابع را بررسی خواهیم کرد.

استفاده از تابع debounce در یک پروژه واقعی

ابتدا با استفاده از کدهای HTML، یک input ایجاد می‌کنیم:

<label for="myInput">Type something in!</label>
<input id="myInput" type="text">

در مرحله بعد، تابعی که می‌خواهیم هر زمان متنی در input وارد شد، اجرا شود را تعریف می‌کنیم:

function helloWorld() {
    console.log("Hello World!")
}

سپس با استفاده از زبان JavaScript، به المنت input خود یک keyup event listener اضافه می‌کنیم:

const myInput = document.getElementById("myInput");

myInput.addEventListener(
    "keyup",
    debounce( helloWorld, 2000 )
);

در نهایت با استفاده از کدهای بالا، اگر از آخرین کلمه‌ای که در input تایپ کرده‌ایم حداقل ۲ ثانیه گذشته باشد، تابع helloWorld اجرا می‌شود.

جمع‌بندی پایانی

توابع debounce بسیار ساده و در عین حال قدرتمند هستند، همچنین می‌توانند تاثیر قابل توجهی در اکثر برنامه‌های JavaScript داشته باشند. با اینکه مثال ما بسیار ساده بود اما سازمان‌های بزرگ از توابع debounce برای افزایش عملکرد برنامه‌هایشان استفاده می‌کنند.

منبع: https://www.freecodecamp.org/news/debounce-explained-how-to-make-your-javascript-wait-for-your-user-to-finish-typing-2