پیادهسازی تابع Debounce در زبان JavaScript
۲۴ آبان ۱۳۹۹
اگر بخواهیم توابع debounce را شرح دهیم میتوان گفت که آنها در دسته توابع higher-order قرار میگیرند و با استفاده از آنها میتوانیم سرعت فراخوانی تابع دیگری را محدود کنیم، مثلا منتظر بمانیم تا تایپ کردن کاربر تمام شود و سپس نتایج را به او نشان دهیم.
توابع higher-order، تابعی را به عنوان ورودی دریافت یا تابعی را return میکنند، اما تابع debounce هر دو کار را انجام میدهد. یکی از معمولترین استفادهها از تابع debounce برای ارسال argument به event listener یک المنت HTML است. برای درک بهتر فایده و ساختار آن، به مثال زیر دقت داشته باشید.
فرض کنید که شما تابعی با نام 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 برای افزایش عملکرد برنامههایشان استفاده میکنند.