วิธีปรับปรุงประสิทธิภาพการค้นหาในการโต้ตอบด้วยการดีเด้ง
ใน React เมื่อใช้ฟังก์ชันการค้นหา ตัวจัดการ onChange จะเรียกใช้ฟังก์ชันการค้นหาทุกครั้งที่ผู้ใช้พิมพ์ในช่องป้อนข้อมูล วิธีการนี้อาจทำให้เกิดปัญหาด้านประสิทธิภาพ โดยเฉพาะอย่างยิ่งหากทำการเรียก API หรือการสืบค้นฐานข้อมูล การเรียกใช้ฟังก์ชันการค้นหาบ่อยครั้งอาจทำให้เว็บเซิร์ฟเวอร์ทำงานหนักเกินไป ส่งผลให้เกิดข้อขัดข้องหรือ UI ที่ไม่ตอบสนอง การดีเด้งจะช่วยแก้ปัญหานี้ได้
การดีเด้งคืออะไร?
ในการใช้งานฟังก์ชันการค้นหาโดยทั่วไปใน React โดยทั่วไปเราจะเรียกใช้ฟังก์ชันตัวจัดการ onChange กับการกดแป้นพิมพ์แต่ละครั้ง ดังที่แสดงด้านล่าง:
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."/>
);
}
เพื่อเพิ่มประสิทธิภาพการทำงาน สิ่งสำคัญคือต้องพิจารณาว่าการอัปเดตผลการค้นหาบ่อยครั้งผ่านการเรียกไปยังแบ็กเอนด์อาจมีค่าใช้จ่ายสูงเมื่อพิมพ์คำหลักเช่น “webdev” ในสถานการณ์นี้ แอปพลิเคชันจะส่งคำขอไปยังส่วนหลังทุกครั้งที่ป้อนอักขระใหม่ รวมถึงอักขระเช่น"w",“เรา”,“เว็บ"ฯลฯ
Debouncing เกี่ยวข้องกับการเลื่อนการดำเนินการของฟังก์ชันออกไปจนกว่ากรอบเวลาที่กำหนดจะผ่านไปนับตั้งแต่การเรียกใช้ครั้งล่าสุด ในสถานการณ์สมมตินี้ ฟังก์ชัน debounced จะถูกทริกเกอร์เมื่อผู้ใช้หยุดพิมพ์หลังจากช่วงเวลาที่ระบุเท่านั้น หากมีการป้อนข้อมูลเพิ่มเติมในช่วงเวลาที่กำหนด ตัวจับเวลาจะรีเซ็ตและเริ่มการประมวลผลอีกรอบ วงจรนี้จะเกิดซ้ำตราบใดที่ไม่มีการป้อนคีย์เพิ่มเติม และจะหยุดลงเมื่อผู้ใช้หยุดกิจกรรมการพิมพ์
การดีเด้งช่วยให้แอปพลิเคชันสามารถจัดการคำขอของเซิร์ฟเวอร์ได้อย่างมีประสิทธิภาพโดยชะลอคำขอเหล่านั้นจนกว่าผู้ใช้จะหยุดป้อนข้อมูล จึงช่วยลดการค้นหาที่ไม่จำเป็นและบรรเทาความเครียดบนเซิร์ฟเวอร์
วิธี Debounce การค้นหาใน React
เมื่อต้องการรวมฟังก์ชัน debouncing ในเว็บแอปพลิเคชัน มีไลบรารีที่มีอยู่แล้วหลายไลบรารีที่ให้ความสามารถนี้ อีกทางหนึ่งอาจเลือกที่จะสร้างอัลกอริธึม debouncer จากพื้นฐานโดยใช้เมธอด setTimeout
และ clearTimeout
ของ JavaScript
บทความนี้ใช้ฟังก์ชัน debouncing ที่จัดทำโดยไลบรารี Lodash ซึ่งเป็นยูทิลิตี JavaScript ยอดนิยมซึ่งมีฟังก์ชันการทำงานที่หลากหลายสำหรับการจัดการข้อมูลและการเพิ่มประสิทธิภาพการดำเนินงาน
เพื่อที่จะเริ่มต้นกระบวนการพัฒนาฟังก์ชันการค้นหาภายในโปรเจ็กต์ React ที่คุณมีอยู่หรือโดยการสร้างอันใหม่ จำเป็นต้องสร้างองค์ประกอบใหม่ชื่อ"Search"ก่อน ซึ่งสามารถทำได้โดยใช้แอปพลิเคชัน React ที่มีอยู่หรือใช้ยูทิลิตี้’สร้างแอป React’เพื่อสร้างสภาพแวดล้อม React ที่ทำงานได้อย่างสมบูรณ์
ในไฟล์ส่วนประกอบการค้นหา เราสามารถใช้ข้อมูลโค้ดที่ให้มาเพื่อสร้างฟิลด์อินพุตการค้นหาซึ่งจะดำเนินการฟังก์ชันเรียกกลับที่กำหนดทุกครั้งที่กดปุ่ม
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."/>
);
}
หากต้องการชะลอการดำเนินการของฟังก์ชัน handleSearch
โดยใช้ฟังก์ชัน debounce
ที่จัดทำโดยไลบรารี Lodash เราสามารถส่งฟังก์ชันดังกล่าวเป็นอาร์กิวเมนต์ไปยังเมธอด debounce
ได้ สิ่งนี้จะช่วยให้มั่นใจได้ว่าฟังก์ชันจะถูกดำเนินการเพียงครั้งเดียวในช่วงเวลาที่กำหนด หลังจากนั้นการโทรที่ตามมาภายในกรอบเวลานั้นจะถูกละเว้นจนกว่าระยะเวลารอจะสิ้นสุดลง
import debounce from "lodash.debounce";
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 1000);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."/>
);
}
ในการดำเนินการตามกลไก debouncing เราขอแนะนำเวอร์ชันที่กำหนดเองของฟังก์ชัน handleSearch
โดยการยอมรับเป็นอาร์กิวเมนต์พร้อมกับช่วงเวลาที่ระบุ ซึ่งก็คือ 500 มิลลิวินาที ซึ่งทำหน้าที่เป็นเกณฑ์ในการทริกเกอร์การดำเนินการล่าช้าของฟังก์ชันดังกล่าว.
โค้ดดังกล่าวคาดว่าจะเลื่อนการดำเนินการของฟังก์ชัน handleSearch
ออกไปจนกว่าผู้ใช้จะสิ้นสุดการป้อนข้อมูล อย่างไรก็ตาม ฟังก์ชันนี้ไม่ทำงานตามที่ตั้งใจไว้ภายในกรอบงาน React สาเหตุของความคลาดเคลื่อนนี้จะมีการสำรวจเพิ่มเติมในส่วนถัดไป
การดีเด้งและการเรนเดอร์
แอปพลิเคชันปัจจุบันใช้อินพุตที่ได้รับการควบคุม โดยที่สภาพที่เป็นอยู่ของระบบจะกำหนดเนื้อหาที่ให้เป็นเอาต์พุตผ่านแถบค้นหา เมื่อผู้ใช้กดแป้นพิมพ์แต่ละครั้งภายในอินเทอร์เฟซเฉพาะนี้ React จะผนวกการแก้ไขการกำหนดค่าของสถานะตามนั้น
React เป็นไลบรารี JavaScript ยอดนิยมที่ใช้สำหรับสร้างส่วนต่อประสานกับผู้ใช้ เมื่อใดก็ตามที่ค่าสถานะในองค์ประกอบ React เปลี่ยนแปลง องค์ประกอบทั้งหมดจะถูกเรนเดอร์ใหม่ ซึ่งเกี่ยวข้องกับการเรียกใช้ฟังก์ชันทั้งหมดตั้งแต่ต้นจนจบอีกครั้ง ซึ่งช่วยให้สามารถอัปเดตแบบไดนามิกไปยังอินเทอร์เฟซได้โดยไม่จำเป็นต้องรีเฟรชทั้งหน้า
องค์ประกอบการค้นหาที่กล่าวมาข้างต้นได้รับการเรนเดอร์ใหม่ในระหว่างที่ React เปิดใช้งานกลไกการดีเด้ง ตัวจับเวลาแบบใหม่ถูกสร้างขึ้นเพื่อตรวจสอบความล่าช้าในขณะที่ตัวจับเวลาที่มีอยู่ยังคงทำงานอยู่ในหน่วยความจำระบบ เมื่อหมดอายุ ฟังก์ชันการค้นหาจะถูกกระตุ้นหลังจากถูกเลื่อนออกไปเป็นเวลา 500 มิลลิวินาที ด้วยเหตุนี้ ลำดับนี้จะเกิดขึ้นซ้ำเมื่อมีการเรนเดอร์แต่ละครั้ง เนื่องจากตัวจับเวลาใหม่มีความสำคัญมากกว่าลำดับก่อนหน้า โดยตัวจับเวลาเก่าจะสิ้นสุดระยะเวลาการยกเลิกในเวลาต่อมาก่อนที่จะเรียกใช้ฟังก์ชันการค้นหาซ้ำๆ
เพื่อให้แน่ใจว่าฟังก์ชัน debounced ทำงานตามที่ตั้งใจไว้ภายในส่วนประกอบ React สิ่งสำคัญคือต้องจำกัดการดำเนินการให้เหลือเพียงอินสแตนซ์เดียว แนวทางหนึ่งในการบรรลุเป้าหมายนี้เกี่ยวข้องกับการใช้เทคนิคการท่องจำร่วมกับฟังก์ชัน debouncing การทำเช่นนี้ แม้ว่าคอมโพเนนต์จะแสดงผลซ้ำ ฟังก์ชัน debounced จะไม่ถูกดำเนินการซ้ำๆ
การกำหนดฟังก์ชั่น Debounce ภายนอกองค์ประกอบการค้นหา
พิจารณาย้ายกลไกการดำเนินการที่เลื่อนออกไป เช่น debounce
ไปยังตำแหน่งนอกคอมโพเนนต์ Search
ดังแสดงในตัวอย่างที่ให้ไว้ด้านล่าง:
import debounce from "lodash.debounce"
const handleSearch = (searchTerm) => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 500);
ในการวนซ้ำปัจจุบันขององค์ประกอบการค้นหาของโปรเจ็กต์ของเรา เราจะใช้ฟังก์ชัน search
ในเวอร์ชัน debounced โดยการเรียกใช้เมธอด debouncedSearch
และจัดเตรียมคำค้นหาเป็นอาร์กิวเมนต์
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."/>
);
}
ฟังก์ชันการทำงานของฟังก์ชันการค้นหาขึ้นอยู่กับการหมดอายุของช่วงเวลาที่กำหนดไว้ล่วงหน้า ซึ่ง ณ จุดนี้ฟังก์ชันดังกล่าวจะถูกเรียกใช้
จดจำฟังก์ชัน Debounce
การจำเกี่ยวข้องกับการจัดเก็บเอาต์พุตที่สร้างโดยฟังก์ชันเฉพาะเมื่อได้รับอินพุตเฉพาะ เพื่อให้สามารถเรียกค้นและใช้งานได้ทันทีหากฟังก์ชันถูกเรียกอีกครั้งด้วยพารามิเตอร์ที่เหมือนกัน เทคนิคนี้ใช้เป็นกลยุทธ์การปรับให้เหมาะสมเพื่อลดค่าใช้จ่ายในการคำนวณ โดยเฉพาะอย่างยิ่งในกรณีที่เกี่ยวข้องกับการคำนวณซ้ำ
หากต้องการแคชและเลื่อนการดำเนินการของฟังก์ชัน debounced อย่างมีประสิทธิภาพโดยใช้กลไก Memoization ของ React ให้ใช้ useMemo Hook ร่วมกับกลยุทธ์การใช้งานที่เหมาะสมสำหรับผล debouncing ที่ต้องการ
import debounce from "lodash.debounce";
import { useCallback, useMemo, useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = useCallback((searchTerm) => {
console.log("Search for:", searchTerm);
}, []);
const debouncedSearch = useMemo(() => {
return debounce(handleSearch, 500);
}, [handleSearch]);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."/>
);
}
สิ่งสำคัญคือต้องทราบว่าเราได้รวมฟังก์ชัน handleSearch
ไว้ในฮุก useCallback
เพื่อรับประกันว่า React จะเรียกใช้ฟังก์ชันนี้เพียงครั้งเดียวเท่านั้น หากไม่ใช่เพราะ hook useCallback
React จะดำเนินการฟังก์ชัน handleSearch
ซ้ำๆ ในระหว่างกระบวนการเรนเดอร์แต่ละครั้ง ส่งผลให้เกิดการเปลี่ยนแปลงการขึ้นต่อกันของ hook useMemo
และผลที่ตามมาก็คือทริกเกอร์ฟังก์ชัน debounce
React จะเรียกใช้ฟังก์ชัน debounced เฉพาะในกรณีที่ฟังก์ชัน handleSearch
หรือช่วงหน่วงเวลามีการเปลี่ยนแปลง
เพิ่มประสิทธิภาพการค้นหาด้วย Debounce
ในบางครั้ง การควบคุมความเร็วอาจนำไปสู่ประสิทธิภาพการผลิตที่เพิ่มขึ้น ในสถานการณ์ที่เกี่ยวข้องกับฐานข้อมูลหรือการสืบค้น API ที่มีราคาแพงในระหว่างดำเนินการค้นหา การใช้ฟังก์ชัน debounce จะต้องใช้ความระมัดระวัง ฟังก์ชันนี้กำหนดให้มีการหยุดชั่วคราวก่อนที่จะส่งต่อคำขอไปยังแบ็กเอนด์
การใช้กลไกการโหลดรูปภาพล่าช้าในหน้าเว็บสามารถแบ่งเบาภาระบนเซิร์ฟเวอร์ได้อย่างมาก โดยการจำกัดความถี่ของคำขอที่ส่งไปยังเซิร์ฟเวอร์เหล่านั้น ด้วยการกำหนดค่าระบบให้รอจนกว่าผู้ใช้จะหยุดอินพุตชั่วคราวก่อนส่งคำขอรูปภาพ เราจะลดปริมาณคำขอที่ประมวลผลพร้อมกันให้เหลือน้อยที่สุด ด้วยเหตุนี้ วิธีการนี้จึงรักษาประสิทธิภาพของเซิร์ฟเวอร์ให้เหมาะสมที่สุดในขณะเดียวกันก็ป้องกันการสิ้นเปลืองทรัพยากรหรือความล่าช้าในเวลาตอบสนอง