ในเหตุการณ์ DOM เบราว์เซอร์เหตุการณ์บางอย่างจะถูกเรียกอย่างต่อเนื่องกับการดำเนินการของผู้ใช้ ตัวอย่างเช่น: ปรับขนาดหน้าต่างเบราว์เซอร์เลื่อนหน้าเบราว์เซอร์และ Mousemove กล่าวคือเมื่อผู้ใช้ทริกเกอร์การทำงานของเบราว์เซอร์เหล่านี้หากวิธีการจัดการเหตุการณ์ที่สอดคล้องกันถูกผูกไว้กับสคริปต์วิธีนี้จะถูกเรียกอย่างต่อเนื่อง
นี่ไม่ใช่สิ่งที่เราต้องการเพราะบางครั้งหากวิธีการจัดการเหตุการณ์มีขนาดค่อนข้างใหญ่การดำเนินงาน DOM เช่นซับซ้อนและการกระตุ้นเหตุการณ์ดังกล่าวอย่างต่อเนื่องจะทำให้เกิดการสูญเสียประสิทธิภาพส่งผลให้ประสบการณ์การใช้งานลดลง (การตอบสนอง UI ช้าเบราว์เซอร์ติดอยู่ ฯลฯ ) ดังนั้นโดยปกติแล้วเราจะเพิ่มตรรกะให้กับเหตุการณ์ที่เกี่ยวข้องเพื่อชะลอการดำเนินการ
โดยทั่วไปเราใช้รหัสต่อไปนี้เพื่อใช้ฟังก์ชั่นนี้:
var count = 0; function testfn () {console.log (count ++); } // เมื่อเบราว์เซอร์ปรับขนาด // 1 ล้างตัวจับเวลาก่อนหน้า // 2 เพิ่มตัวจับเวลาเพื่อชะลอฟังก์ชันจริง testfn โดย 100 มิลลิวินาทีเพื่อทริกเกอร์หน้าต่าง onResize = function () {ตัวจับเวลา var = null; ClearTimeout (ตัวจับเวลา); timer = settimeout (function () {testfn ();}, 100);};นักเรียนระวังจะพบว่ารหัสข้างต้นนั้นผิดจริง นี่เป็นปัญหาที่สามเณรจะทำ: ค่าส่งคืนของฟังก์ชั่น settimeout ควรถูกบันทึกไว้ในตัวแปรระดับโลกที่สัมพันธ์กันมิฉะนั้นจะมีการสร้างตัวจับเวลาใหม่ทุกครั้งที่ปรับขนาดขนาดซึ่งจะไม่บรรลุผลที่เราส่ง
ดังนั้นเราจึงแก้ไขรหัส:
var timer = null; window.onResize = function () {clearTimeout (ตัวจับเวลา); timer = settimeout (function () {testfn ();}, 100);};ในเวลานี้รหัสเป็นเรื่องปกติ แต่มีปัญหาใหม่อีกอย่างหนึ่ง - ตัวจับเวลาตัวแปรทั่วโลกถูกสร้างขึ้น นี่คือสิ่งที่เราไม่อยากเห็น หากหน้านี้มีฟังก์ชั่นอื่น ๆ จะเรียกว่าตัวจับเวลา รหัสที่แตกต่างกันจะทำให้เกิดความขัดแย้งมาก่อน เพื่อแก้ปัญหานี้เราจำเป็นต้องใช้คุณสมบัติภาษาของ JavaScript: ปิดการปิด ผู้อ่านสามารถเรียนรู้เกี่ยวกับความรู้ที่เกี่ยวข้องใน MDN รหัสที่แก้ไขมีดังนี้:
/*** ฟังก์ชั่นวิธีการควบคุมปริมาณ* ฟังก์ชั่น @param fn fn การโทรล่าช้าฟังก์ชั่น* @param number delay วิธีการหน่วงเวลา* @return ใช้เวลานานเท่าใดวิธีการทำงานสำหรับการล่าช้าการดำเนินการ*/var throttle = ฟังก์ชั่น (fn, ล่าช้า) {var timer = null; return function () {cleartimeout (ตัวจับเวลา); timer = settimeout (function () {fn ();}, ล่าช้า); }}; window.onresize = เค้น (testfn, 200, 1000);เราใช้ฟังก์ชั่นการปิด (การควบคุมคันเร่ง) เพื่อวางตัวจับเวลาภายในและส่งคืนฟังก์ชั่นการประมวลผลการหน่วงเวลา ด้วยวิธีนี้ตัวแปรตัวจับเวลาจะมองไม่เห็นด้านนอก แต่ตัวแปรตัวจับเวลาสามารถเข้าถึงได้เมื่อฟังก์ชั่นการหน่วงเวลาภายในถูกทริกเกอร์
แน่นอนว่าวิธีการเขียนนี้ไม่ใช่เรื่องง่ายสำหรับสามเณรที่จะเข้าใจ เราสามารถเปลี่ยนวิธีการเขียนเพื่อทำความเข้าใจ:
var throttle = function (fn, delay) {var timer = null; return function () {cleartimeout (ตัวจับเวลา); timer = settimeout (function () {fn ();}, ล่าช้า); }}; var f = เค้น (testfn, 200); window.onresize = function () {f ();};นี่คือมุมมอง: ฟังก์ชั่นที่ส่งคืนโดยคันเร่งหลังจากถูกเรียกว่าเป็นฟังก์ชั่นจริงที่ต้องเรียกเมื่อมีการเรียกใช้ onresize
ตอนนี้ดูเหมือนว่าวิธีนี้ใกล้เคียงกับความสมบูรณ์แบบ แต่ไม่ใช่กรณีในการใช้งานจริง ตัวอย่างเช่น:
หากผู้ใช้ปรับขนาดขนาดหน้าต่างเบราว์เซอร์อย่างต่อเนื่องฟังก์ชั่นการประมวลผลการหน่วงเวลาจะไม่ถูกดำเนินการครั้งเดียว
ดังนั้นเราจำเป็นต้องเพิ่มฟังก์ชั่นอื่น: เมื่อผู้ใช้ทริกเกอร์ปรับขนาดมันควรจะถูกเรียกอย่างน้อยหนึ่งครั้งภายในระยะเวลาหนึ่ง เนื่องจากภายในระยะเวลาหนึ่งเงื่อนไขการตัดสินนี้อาจใช้เวลามิลลิวินาทีในปัจจุบันและแต่ละฟังก์ชั่นเรียกใช้เวลาปัจจุบันจากเวลาการโทรครั้งสุดท้ายและจากนั้นตัดสินว่าหากความแตกต่างมากกว่าระยะเวลาหนึ่งมันจะถูกส่งโดยตรง
สิ่งที่ต้องชี้ให้เห็นในรหัสต่อไปนี้คือ:
1. ฟังก์ชั่นของตัวแปรก่อนหน้านี้คล้ายกับของตัวจับเวลา พวกเขาทั้งสองบันทึกตัวระบุล่าสุดและจะต้องเป็นตัวแปรทั่วโลกที่สัมพันธ์กัน
2. หากกระบวนการลอจิกเป็นไปตามตรรกะ "ทริกเกอร์อย่างน้อยหนึ่งครั้ง" ดังนั้นการเรียกใช้ฟังก์ชันจะต้องเสร็จสิ้นเพื่อรีเซ็ตก่อนหน้านี้เป็นเวลาปัจจุบัน พูดง่ายๆคือ: เปรียบเทียบกับครั้งสุดท้ายครั้งสุดท้ายมันเป็นเรื่องปัจจุบัน
/*** ฟังก์ชั่นวิธีการควบคุมปริมาณ* @param ฟังก์ชั่นการโทรล่าช้าฟังก์ชั่น* @param หมายเลขล่าช้าระยะเวลานานเท่าใด* @param หมายเลขอย่างน้อยระยะเวลาที่เรียกใช้* @return function วิธีการสำหรับการล่าช้าการดำเนินการ*/var throttle = ฟังก์ชั่น (fn, ล่าช้าอย่างน้อย) {var timer = null; var previous = null; return function () {var now = +date ใหม่ (); ถ้า (ก่อนหน้า) ก่อนหน้า = ตอนนี้; if (ตอนนี้ - ก่อนหน้า> อย่างน้อย) {fn (); // รีเซ็ตเวลาเริ่มต้นสุดท้ายเป็นเวลาสิ้นสุดของเวลานี้ก่อนหน้า = ตอนนี้; } else {cleartimeout (ตัวจับเวลา); timer = settimeout (function () {fn ();}, ล่าช้า); -ฝึกฝน:
เราจำลองฉากการควบคุมปริมาณเมื่อหน้าต่างเลื่อนนั่นคือเมื่อผู้ใช้เลื่อนหน้าลงเราจำเป็นต้องควบคุมปริมาณวิธีการบางอย่างเช่น: การคำนวณตำแหน่ง DOM ฯลฯ ซึ่งต้องใช้การทำงานอย่างต่อเนื่องขององค์ประกอบ DOM
รหัสที่สมบูรณ์มีดังนี้:
<! doctype html> <html lang = "en"> <head> <meta charset = "utf-8"> <title> throttle </title> </head> <body> <div style = "ความสูง: 5000px"> Document.getElementById ('Demo'); function testfn () {demo.innerhtml += 'testfn ถูกเรียกว่า' +++ count +'เวลา <br>';} var throttle = ฟังก์ชั่น (fn, ล่าช้าอย่างน้อย) {var timer = null; var previous = null; return function () {var now = +date ใหม่ (); ถ้า (ก่อนหน้า) ก่อนหน้า = ตอนนี้; ถ้า (อย่างน้อย && ตอนนี้ - ก่อนหน้า> อย่างน้อย) {fn (); // รีเซ็ตเวลาเริ่มต้นสุดท้ายเป็นเวลาสิ้นสุดของเวลานี้ก่อนหน้า = ตอนนี้; ClearTimeout (ตัวจับเวลา); } else {cleartimeout (ตัวจับเวลา); timer = settimeout (function () {fn (); previous = null;}, ล่าช้า); - window.onscroll = เค้น (testfn, 200); // window.onscroll = เค้น (testfn, 500, 1000); </script> </body> </html>เราใช้สองกรณีเพื่อทดสอบเอฟเฟกต์คือการเพิ่มอย่างน้อยทริกเกอร์อย่างน้อยก็อย่างน้อยและไม่เพิ่ม:
// กรณี 1window.onscroll = เค้น (testfn, 200); // case 2window.onscroll = เค้น (testfn, 200, 500);
กรณีที่ 1 จะปรากฏเป็น: testFN จะไม่ถูกเรียกในระหว่างกระบวนการเลื่อนหน้า (ไม่สามารถหยุดได้) และจะถูกเรียกอีกครั้งจนกว่าจะหยุดซึ่งหมายความว่าการตั้งถิ่นฐานครั้งสุดท้ายในคันเร่งจะถูกดำเนินการและเอฟเฟกต์ดังแสดงในรูป (ดูภาพ GIF ดั้งเดิม):
กรณีที่ 2 ปรากฏเป็น: ในระหว่างกระบวนการเลื่อนหน้า (ไม่สามารถหยุดได้) testFN จะล่าช้า 500ms เป็นครั้งแรก (จากตรรกะการหน่วงเวลาอย่างน้อย) จากนั้นดำเนินการอย่างน้อยทุก 500ms เอฟเฟกต์ดังแสดงในรูปที่แสดงในรูป
จนถึงตอนนี้ผลลัพธ์ที่เราต้องการบรรลุนั้นเสร็จสมบูรณ์โดยทั่วไป ผู้อ่านสามารถคิดเกี่ยวกับการเพิ่มประสิทธิภาพเสริมที่ตามมาด้วยตัวเองเช่น: ฟังก์ชั่นการชี้นี้การประหยัดค่าคืน ฯลฯ
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น