您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“JS防抖節(jié)流函數(shù)的實現(xiàn)與使用方式”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
一、什么是函數(shù)防抖
1、為什么需要函數(shù)防抖?
2、函數(shù)防抖的要點
3、函數(shù)防抖的實現(xiàn)
4、函數(shù)防抖的使用場景
二、什么是函數(shù)節(jié)流
1、函數(shù)節(jié)流的要點
2、函數(shù)節(jié)流的實現(xiàn)
3、函數(shù)節(jié)流的使用場景
概念:函數(shù)防抖(debounce),就是指觸發(fā)事件后,在 n 秒內(nèi)函數(shù)只能執(zhí)行一次,如果觸發(fā)事件后在 n 秒內(nèi)又觸發(fā)了事件,則會重新計算函數(shù)延執(zhí)行時間。
前端開發(fā)過程中,有一些事件,常見的例如,onresize,scroll,mousemove ,mousehover 等,會被頻繁觸發(fā)(短時間內(nèi)多次觸發(fā)),不做限制的話,有可能一秒之內(nèi)執(zhí)行幾十次、幾百次,如果在這些函數(shù)內(nèi)部執(zhí)行了其他函數(shù),尤其是執(zhí)行了操作 DOM 的函數(shù)(瀏覽器操作 DOM 是很耗費性能的),那不僅會浪費計算機資源,還會降低程序運行速度,甚至造成瀏覽器卡死、崩潰。
函數(shù)防抖的要點,是需要一個 setTimeout 來輔助實現(xiàn),延遲運行需要執(zhí)行的代碼。如果方法多次觸發(fā),則把上次記錄的延遲執(zhí)行代碼用 clearTimeout 清掉,重新開始計時。若計時期間事件沒有被重新觸發(fā),等延遲時間計時完畢,則執(zhí)行目標(biāo)代碼。
//HTML部分 <div> 賬戶:<input type="text" id="myinput"> </div>
//JS部分 function debounce(fun,wait=1500){//ES6語法 wait=1500 設(shè)置參數(shù)默認(rèn)值,如果沒有輸入wait就會使用1500 let timeout = null return function(){ if(timeout){//如果存在定時器就清空 clearTimeout(timeout) } timeout=setTimeout(function(){ fun() },wait) } } function testUname(){ console.log("輸入結(jié)束!") } document.getElementById('myinput').addEventListener('input',debounce(testUname,1000))
上面的代碼就是防抖函數(shù)的簡單運用,只要你每次輸入間隔大于一秒,那么永遠(yuǎn)不會打“印輸入結(jié)束!”,直到你停止輸入嗎,這是因為每一次的輸入都會清除上一次的計時器。
看到這里你以為就結(jié)束了嗎?別急,讓我們繼續(xù)看:
//HTML部分 <div> 賬戶:<input type="text" id="myinput"> </div>
//JS部分 function debounce(fun,wait=1500){ let timeout = null return function(){ console.log(this)//<input id="myinput" type="text"> console.log(arguments)//Arguments { 0: input, … } if(timeout){//如果存在定時器就清空 clearTimeout(timeout) } timeout=setTimeout(function(){ console.log(this)//Window console.log(arguments)//Arguments { … } fun() },wait) } } function testUname(){ console.log("輸入結(jié)束!") } document.getElementById('myinput').addEventListener('input',debounce(testUname,1000))
無論是防抖還是節(jié)流,我們都要解決兩個問題,this指向和arguments。
如果沒有特殊指向,setInterval和setTimeout的回調(diào)函數(shù)中this的指向都是window。這是因為JS的定時器方法是定義在window下的。這顯然不是我們希望的,因為我們監(jiān)聽的是input輸入框,所以我們希望定時器里面的this指向input。
那么有什么方法可以改變this指向嗎?
一種簡單的辦法就是我們可以用參數(shù)把定時器外層函數(shù)的this和arguments保存下來。然后再通過apply改變定時器要執(zhí)行的函數(shù)fun的指向。
//JS部分 function debounce(fun,wait=1500){ let timeout = null return function(){ let _this = this let arg = arguments if(timeout){//如果存在定時器就清空 clearTimeout(timeout) } timeout=setTimeout(function(){ console.log(_this)//<input id="myinput" type="text"> console.log(arg)//Arguments { 0: input, … } fun.apply(_this,arg) },wait) } }
當(dāng)然,你也可以用ES6的箭頭函數(shù)新特性:箭頭函數(shù)的 this 始終指向函數(shù)定義時的 this,而非執(zhí)行時。箭頭函數(shù)需要記著這句話:“箭頭函數(shù)中沒有 this 綁定,必須通過查找作用域鏈來決定其值,如果箭頭函數(shù)被非箭頭函數(shù)包含,則 this 綁定的是最近一層非箭頭函數(shù)的 this,否則,this 為 undefined”。
所以也可以這樣寫:
//JS部分 function debounce(fun,wait=1500){ let timeout = null return function(){ if(timeout){//如果存在定時器就清空 clearTimeout(timeout) } timeout=setTimeout(()=>{ console.log(this)//<input id="myinput" type="text"> console.log(arguments)//Arguments { 0: input, … } fun.apply(this,arguments) },wait) } }
函數(shù)防抖一般用在什么情況之下呢?一般用在,連續(xù)的事件只需觸發(fā)一次回調(diào)的場合。具體有:
搜索框搜索輸入。只需用戶最后一次輸入完,再發(fā)送請求;
用戶名、手機號、郵箱輸入驗證;
瀏覽器窗口大小改變后,只需窗口調(diào)整完后,再執(zhí)行 resize 事件中的代碼,防止重復(fù)渲染。
概念: 限制一個函數(shù)在一定時間內(nèi)只能執(zhí)行一次。
舉個栗子,坐火車或地鐵,過安檢的時候,在一定時間(例如10秒)內(nèi),只允許一個乘客通過安檢入口,以配合安檢人員完成安檢工作。上例中,每10秒內(nèi),僅允許一位乘客通過,分析可知,“函數(shù)節(jié)流”的要點在于,在 一定時間 之內(nèi),限制 一個動作 只 執(zhí)行一次 。
主要實現(xiàn)思路就是通過 setTimeout 定時器,通過設(shè)置延時時間,在第一次調(diào)用時,創(chuàng)建定時器,先設(shè)定一個變量,然后把定時器賦值給這個變量,再寫入需要執(zhí)行的函數(shù)。第二次執(zhí)行這個函數(shù)時,會判斷變量是否true,是則返回。當(dāng)?shù)谝淮蔚亩〞r器執(zhí)行完函數(shù)最后會設(shè)定變量為false。那么下次判斷變量時則為false,函數(shù)會依次運行。目的在于在一定的時間內(nèi),保證多次函數(shù)的請求只執(zhí)行最后一次調(diào)用。
這么看是不是有點看不懂?讓我們來看代碼:
//JS部分 function debounce(fun,wait=1000){//定時器方案 let timer = null;//先設(shè)定一個變量 return function(){ if(!timer){//如果timer為null就進入 timer = setTimeout(function(){//然后把定時器賦值給這個變量 fun()//再寫入需要執(zhí)行的函數(shù) timer = null//第一次的定時器執(zhí)行完函數(shù)最后會設(shè)定變量為false,這里的 timer = null有兩個作用,1、開啟下一次的入口,2、清除后面的定時器 }) } } } function testUname(){ console.log(Math.random()) } document.getElementById('myinput').addEventListener('input',debounce(testUname))
同樣的,節(jié)流函數(shù)也要解決this和arguments的問題,改進后如下:
//箭頭函數(shù)寫法 function debounce(fun,wait=1000){ let timer = null return function(){ if(!timer){ timer = setTimeout(()=>{ fun.apply(this,arguments) timer = null },wait) } } } //參數(shù)保存法 function debounce(fun,wait=1000){ let timer = null return function(){ let _this = this let arg = arguments if(!timer){ timer = setTimeout(function(){ fun.apply(_this,arg) timer = null },wait) } } }
到此為止,相信各位應(yīng)該對函數(shù)節(jié)流有了一個比較詳細(xì)的了解,那函數(shù)節(jié)流一般用在什么情況之下呢?
懶加載、滾動加載、加載更多或監(jiān)聽滾動條位置;
百度搜索框,搜索聯(lián)想功能;
防止高頻點擊提交,防止表單重復(fù)提交;
“JS防抖節(jié)流函數(shù)的實現(xiàn)與使用方式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。