Pertama, mari kita mengerti apa itu throttle
1. Definisi
Jika Anda mengencangkan keran sampai air mengalir keluar dalam bentuk tetesan air, Anda akan menemukan bahwa sesekali, setetes air akan mengalir keluar.
Dengan kata lain, siklus eksekusi diatur terlebih dahulu, dan ketika waktu ketika tindakan dipanggil lebih besar atau sama dengan siklus eksekusi, tindakan dieksekusi, dan kemudian siklus baru berikutnya dimasukkan.
Definisi Antarmuka:
* Ketika kontrol frekuensi mengembalikan fungsi disebut terus menerus, frekuensi eksekusi tindakan terbatas pada waktu/ penundaan* @param delay {angka} waktu tunda, unit milidetik* @param action {function} meminta fungsi yang terkait, dan fungsi yang perlu dipanggil dalam aplikasi aktual* @return {function} mengembalikan fungsi panggilan klien*/ Throttle (Tindakan), ACTION (return {function} Mengembalikan fungsi panggilan klien*/ Throttle (2. Implementasi sederhana
var throttle = function (delay, action) {var last = 0 retReTurn function () {var Curr = +new date () if (Curr - last> Delay) {action.Apply (ini, argumen) terakhir = Curr}}}Izinkan saya menjelaskan fungsi pelambatan ini dengan cermat di bawah ini.
Dalam acara DOM browser, beberapa acara akan dipicu terus menerus dengan operasi pengguna. Misalnya: Ubah mengubah jendela browser, gulir halaman browser, dan mousemove. Artinya, ketika pengguna memicu operasi browser ini, jika metode penanganan acara yang sesuai terikat pada skrip, metode ini akan dipicu terus menerus.
Ini bukan yang kita inginkan, karena kadang -kadang jika metode penanganan peristiwa relatif besar, operasi DOM seperti kompleks, dan terus -menerus memicu peristiwa semacam itu akan menyebabkan kerugian kinerja, mengakibatkan penurunan pengalaman pengguna (respons UI lambat, browser macet, dll.). Jadi biasanya kami akan menambahkan logika ke acara yang sesuai untuk menunda eksekusi.
Secara umum, kami menggunakan kode berikut untuk mengimplementasikan fungsi ini:
var count = 0; function testfn () {console.log (count ++); } // Ketika browser mengubah ukuran // 1. Hapus timer sebelumnya // 2. Tambahkan timer untuk menunda fungsi nyata testfn dengan 100 milidetik untuk memicu window.onresize = function () {var timer = null; ClearTimeout (timer); timer = setTimeout (function () {testfn ();}, 100);};Siswa yang cermat akan menemukan bahwa kode di atas sebenarnya salah. Ini adalah masalah yang akan dibuat oleh para pemula: Nilai pengembalian fungsi SetTimeout harus disimpan dalam variabel global relatif, jika tidak timer baru akan dihasilkan setiap kali mengubah ukuran diubah ukurannya, yang tidak akan mencapai efek yang kami kirim.
Jadi kami memodifikasi kode:
var timer = null; window.onresize = function () {clearTimeout (timer); timer = setTimeout (function () {testfn ();}, 100);};Pada saat ini, kode tersebut normal, tetapi ada masalah baru lainnya - timer variabel global dihasilkan. Ini adalah sesuatu yang tidak ingin kami lihat. Jika halaman ini memiliki fungsi lain, itu juga disebut timer. Kode yang berbeda akan menyebabkan konflik sebelumnya. Untuk mengatasi masalah ini, kita perlu menggunakan fitur bahasa JavaScript: penutupan penutupan. Pembaca dapat belajar tentang pengetahuan terkait di MDN. Kode yang dimodifikasi adalah sebagai berikut:
/*** Metode throttling fungsi* @param fungsi fn penundaan fungsi panggilan* @param nomor tunda berapa lama metode penundaan* @return untuk menunda eksekusi*/var throttle = fungsi (fn, tunda) {var timer = null; return function () {clearTimeout (timer); timer = setTimeout (function () {fn ();}, tunda); }}; window.onresize = throttle (testfn, 200, 1000);Kami menggunakan fungsi penutupan (throttle throttling) untuk menempatkan timer secara internal dan mengembalikan fungsi pemrosesan penundaan. Dengan cara ini, variabel timer tidak terlihat ke luar, tetapi variabel timer juga dapat diakses ketika fungsi penundaan internal dipicu.
Tentu saja, metode penulisan ini tidak mudah untuk dipahami oleh pemula. Kita dapat mengubah metode penulisan untuk memahami:
var throttle = function (fn, delay) {var timer = null; return function () {clearTimeout (timer); timer = setTimeout (function () {fn ();}, tunda); }}; var f = throttle (testfn, 200); window.onresize = function () {f ();};Berikut adalah sudut pandang: fungsi yang dikembalikan oleh throttle setelah dipanggil adalah fungsi nyata yang perlu dipanggil ketika onressize dipicu
Sekarang tampaknya metode ini dekat dengan kesempurnaan, tetapi tidak demikian halnya dalam penggunaan aktual. Misalnya:
Jika pengguna terus mengubah ukuran jendela browser, fungsi pemrosesan penundaan tidak akan dieksekusi sekali
Jadi kita perlu menambahkan fungsi lain: Ketika pengguna memicu mengubah ukuran, itu harus dipicu setidaknya sekali dalam periode waktu tertentu. Karena dalam periode waktu tertentu, kondisi penilaian ini dapat memakan waktu milidetik saat ini, dan setiap fungsi panggilan mengurangi waktu saat ini dari waktu panggilan terakhir, dan kemudian menilai bahwa jika perbedaannya lebih besar dari periode waktu tertentu, itu akan dikirim secara langsung, jika tidak, ia akan tetap mengikuti logika penundaan batas waktu.
Apa yang perlu ditunjukkan dalam kode berikut adalah:
Fungsi variabel sebelumnya mirip dengan timer. Keduanya adalah pengidentifikasi yang merekam terakhir kali dan harus berupa variabel global relatif
Jika proses logika mengikuti logika "dipicu setidaknya sekali", maka panggilan fungsi harus diselesaikan untuk mengatur ulang sebelum waktu saat ini. Singkatnya, sebenarnya yang saat ini dibandingkan dengan waktu berikutnya.
/*** Fungsi Metode Throttling* @param Fungsi FN Delay Call Function* @param Nomor Tunda Berapa lama penundaan* @param nomor setidaknya berapa lama dipicu* @Return Function Metode untuk menunda eksekusi*/var throttle = function (fn, tunda, setidaknya) {var timer = null; var sebelumnya = null; return function () {var now = +new date (); if (! sebelumnya) sebelumnya = sekarang; if (sekarang - sebelumnya> setidaknya) {fn (); // Setel ulang waktu mulai terakhir hingga akhir waktu ini sebelumnya = sekarang; } else {cleartimeout (timer); timer = setTimeout (function () {fn ();}, tunda); }}};praktik:
Kami mensimulasikan adegan pelambatan ketika sebuah jendela menggulir, yaitu, ketika pengguna menggulir halaman ke bawah, kami perlu mencekik beberapa metode, seperti: menghitung posisi DOM, dll., Yang membutuhkan pengoperasian elemen DOM yang berkelanjutan.
Kode lengkapnya adalah sebagai berikut:
<! Doctype html> <html lang = "en"> <head> <meta charset = "utf-8"> <itement> throttle </ title> </pead> <body> <div style = "tinggi: 5000px"> <div id = "Demo" style = "posisi: tetap;"> </div> </div> varel = demo = gaya = "Posisi: fixed;"> </div> </div> var lrip = Demo = Posisi = Posisi: Fixed; "> </Div> </Div> DOCKED = DOKUM = POSED = POSITE; function testfn () {demo.innerHtml += 'testfn disebut' +++ count +'waktu <br>';} var throttle = fungsi (fn, tunda, setidaknya) {var timer = null; var sebelumnya = null; return function () {var now = +new date (); if (! sebelumnya) sebelumnya = sekarang; if (setidaknya && sekarang - sebelumnya> setidaknya) {fn (); // Setel ulang waktu mulai terakhir hingga akhir waktu ini sebelumnya = sekarang; ClearTimeout (timer); } else {cleartimeout (timer); timer = setTimeout (function () {fn (); sebelumnya = null;}, tunda); }}}}; window.onscroll = throttle (testfn, 200); // window.onscroll = throttle (testfn, 500, 1000); </script> </body> </html>Kami menggunakan dua kasus untuk menguji efeknya, yaitu menambahkan setidaknya memicu setidaknya setidaknya dan tidak menambahkan:
// case 1window.onscroll = throttle (testfn, 200); // case 2window.onscroll = throttle (testfn, 200, 500);
Kasus 1 bermanifestasi sebagai: testfn tidak akan dipanggil selama proses pengguliran halaman (tidak dapat dihentikan), dan akan dipanggil sekali sampai berhenti, yang berarti bahwa pengaturan terakhir dalam throttle dieksekusi, efeknya seperti yang ditunjukkan pada gambar:
Kasus 2 dimanifestasikan sebagai: Selama proses pengguliran halaman (tidak dapat dihentikan), testfn akan ditunda 500ms untuk pertama kalinya (dari setidaknya logika penundaan), dan kemudian menjalankan setidaknya setiap 500ms. Efeknya seperti yang ditunjukkan pada gambar
Seperti yang ditunjukkan di atas, efek yang ingin kami capai telah diperkenalkan dan contoh disediakan. Saya harap ini akan membantu teman yang membutuhkan. Pembaca dapat memikirkan beberapa optimasi tambahan berikutnya sendiri, seperti: berfungsi menunjuk ini, penghematan nilai pengembalian, dll. Lagi pula, rasanya menyenangkan untuk memahami proses ini dengan cermat!