Skip to main content

Debouncing คืออะไร ?

· 4 min read
Kongvut Sangkla

Intro

สวัสดีครับ บทความนี้จะพามารู้จักกับ Debouncing โดย Debouncing เป็นเทคนิคที่มีประโยชน์ในการเพิ่มประสิทธิภาพ Performance ของ Client-side applications โดยเป็นหนึ่งเทคนิคในหลายสิ่งที่สำคัญในการพัฒนา Web App และ Software ซึ่งตามปกติโปรแกรมเมอร์จำเป็นต้องเขียนโค้ดโปรแกรมโดยคำนึง Performance เพื่อที่จะเพิ่มประสบการณ์ผู้ใช้งานที่ดี (UX) กับ Software

พื้นฐานเรื่อง Event Listeners

ก่อนที่จะไปดูว่า Debouncing คืออะไรมาทำความเข้าใจเกี่ยวกับ Event listeners ก่อน

Syntax
element.addEventListener(event, callbackFunction);

ในการพัฒนา Client-side Applications นั้นจะมีเรื่อง Event listeners คือสิ่งที่ขาดไม่ได้สำหรับการ Interacts กับผู้ใช้งานโดยตัวอย่างของ Events เช่น

  • การคลิกปุ่ม
  • การ Scrolling หน้า
  • การกรอกข้อความกับช่อง Input field
  • submit ฟอร์ม และอื่น ๆ

โดย Event listeners จะมี Callback function เพื่อใช้ Triggers เมื่อเกิด Events ต่าง ๆ

จากตัวอย่างด้านล่างนี้จะเห็นว่าทุก ๆ ครั้งที่มี Events ที่ Input จะเกิด Requests (API) = จำนวนของ Events

ปัญหา Callbacks จำนวนมากจาก Event listeners

ในบางโอกาส Event listeners เหล่านี้มักจะเกิดขึ้นจำนวนมากทำให้มีปัญหาเรื่องประสิทธิภาพเมื่อถูกเรียก Callbacks ดังนั้นควรมีการควบคุม Callbacks เหล่านี้เท่าที่จำเป็นจึงเป็นที่มาของเทคนิค Debouncing

แก้ปัญหาด้วย Debouncing

แนวคิด Debouncing

Debouncing คือการหน่วงเวลา (Delay) ในระยะหนึ่งก่อนที่จะให้ทำงานใด ๆ โดยมีเงื่อนไขดังนี้

  • จะทำงานเมื่อหมดเวลาของ Delay และ User ไม่มีการกระทำใด ๆ กับ Input interface และเกิด Event
  • แต่เมื่อ User มีการกระทำใด ๆ กับ Input ก่อนหมดเวลา Delay ค่าของ Delay จะเริ่มต้นใหม่เสมอ
  • ค่าของ Delay จะเริ่มต้นใหม่ไปเรื่อย ๆ จนกว่า User ไม่มีการกระทำใด ๆ กับ Input

จากตัวอย่างด้านล่างเป็นการใช้ Timeout เพื่อกำหนด Delay 500 ms เมื่อเกิด Events ใด ๆ เพื่อให้หน่วงการทำงาน (ไม่ให้ทำงานทันที)

เพราะว่าอาจจะเกิด Events อื่น ๆ ก่อนที่จะให้ทำงานจริง ๆ (เช่น การพิมพ์ตัวอักษรหลาย ๆ ตัวที่พิมพ์ยังไม่เสร็จ) ทำให้การ httpRequest() จะยังไม่ทำงานทันที

จากนั้นเมื่อสิ้นสุด Delay 500 ms และไม่เกิด Events ใด ๆ อีกโปรแกรมก็จะทำงานตาม Callback ที่กำหนดไว้คือ httpRequest()

อธิภายการทำงานจากรูปภาพ

  • Regular คือวิธีแบบปกติที่ไม่ใช้เทคนิค Debouncing โดยทุก ๆ Events จะเกิด Execute
  • Debounce คือวิธีแบบที่ใช้เทคนิค Debouncing โดยทุก ๆ Events จะไม่ทำงานทันทีจนกว่าจะเลิกทำกระทำกับ Input แล้วครบ Delay จึงจะ Execute
แนวคิดของ Debouncing
// เพิ่มกำหนดตัวแปร Timeout ขึ้นมาตัวนึง
let timeout;

inputField.addEventListener('input', () => {
// เมื่อเกิด Events ของ Input ให้ Reset ค่าใน Timeout
clearTimeout(timeout)
// เมื่อสิ้นสุด Delay 500 ms จะทำงานตาม Callback ที่กำหนดไว้คือ httpRequest()
timeout = setTimeout(httpRequest, 500)
})

Use cases การนำไปใช้

  1. ใช้ Debouncing กับการ Resize รูปภาพ
  2. ใช้ Debouncing กับ Event ที่มีคุณสมบัติ Autosave
  3. เพื่อไม่ต้องการให้เกิดการทำงานอื่น ๆ ในขณะเกิด Drags and drops event
  4. เพื่อไม่ให้มี Requests (Axios) ใด ๆ จนกระทั้งผู้ใช้งานหยุดกระทำกับ Input

Debouncing with Helper functions

ส่วนนี้คือเทคนิคที่แถมเพิ่มโดยแทนที่จะเขียน Debouncing แบบ Manual ทุกรอบเราสามารถสร้าง Helper functions ที่ช่วยให้ง่ายและสะดวกในการเรียกใช้งานบ่อย ๆ ดังนี้

// helper.js
export function debounce(callback, delay) {
let timeout

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

// ตัวอย่างการใช้งาน
import { debounce } from '/helper.js'

debounce(httpRequest(), 600)

Debouncing with Lodash

ในภาษา JS เราไม่จำเป็นต้อง Implement Debouncing เองให้เสียเวลา โดยเราสามารถใช้ Library ของ Lodash ช่วยดังนี้

import _ from "lodash"

const logHi = () => console.log('Hi')

const debouncedLogHi = _.debounce(logHi, 1500)

debouncedLogHi()
debouncedLogHi()
debouncedLogHi()

// output: Hi
import _ from "lodash"

const logMessage = message => console.log(message)

const debouncedLogMessage = _.debounce(logMessage, 1500)

debouncedLogMessage('first message')
debouncedLogMessage('second message')
debouncedLogMessage('third message')

// output: third message

Debouncing with React

Basically

ตัวอย่างการใช้ Debouncing กับ React โดยพื้นฐาน (แบบไม่ใช้ Libs)

Live Editor
Result
Loading...

by Lodash

นี่คือตัวอย่างการใช้ Debouncing ใน React และใช้ Library จาก Lodash

แต่จะมีการใช้ useMemo และ useCallback เข้ามาช่วยป้องกันปัญหาเรื่อง Re-renders ที่ส่งผลต่อประสิทธิภาพ

อ่านเนื้อหาเพิ่มเติมเกี่ยวกับการใช้งาน useMemo และ useCallback อย่างละเอียดได้ที่นี่ "การใช้งานและความแตกต่างระหว่าง useMemo และ useCallback ของ React Hooks"

import _ from "lodash"

const { debounce } = _

() => {
// Request statement
function httpRequest(input) {
// Call API ...
}

// ใช้แบบนี้ก็ได้ แต่จะมีปัญหาเรื่อง Re-renders
//const debouncedInputHandler = debounce(inputHandler, 500)

// แนะนำให้ใช้ useCallback เข้ามาช่วยลดปัญหา Re-renders และให้ประสิทธิภาพที่ดีกว่า
const debouncedInputHandler = useCallback(
debounce(inputHandler, 500), []
)

// หรือจะใช้ useMemo ก็ได้เช่นกัน
/*const debouncedInputHandler = useMemo(() => {
return debounce(changeHandler, 500);
}, []);*/

const inputHandler = (event) => {
const input = event.target.value
httpRequest(input)
}

return (
<>
<input type="text" onInput={debouncedInputHandler}></input>
</>
)
}

สรุป

info

แนวคิดเทคนิค Debouncing นั้นไม่ได้จำกัดใช้กับเฉพาะ Frontend App ใน Backend App ก็สามารถใช้เทคนิค Debouncing สำหรับประยุกต์การทำ Delay สำหรับ Processing ได้เหมือนกัน

Debouncing เป็นเทคนิคที่เรียบง่ายและเข้าใจง่าย และยังช่วยปรับปรุงประสิทธิภาพอย่างมาก หวังว่าผู้อ่านจะสามารถปฏิบัติและนำแนวคิดนี้ไปใช้ได้ โดยบทความต่อไปจะพูดถึงอีกเทคนิคที่คล้าย ๆ กันคือ Throttling

*อัปเดทเนื้อหา

References

Loading...