一丶基本概念html
防抖(debounce):在函數須要頻繁觸發時,只有當有足夠空閒的時間時,才執行一次。就好像在百度搜索時,每次輸入以後都有聯想詞彈出,這個控制聯想詞的方法就不多是輸入框內容一改變就觸發的,他必定是當你結束輸入一段時間以後纔會觸發。ajax
節流(thorttle):預約一個函數只有在大於等於執行週期時才執行,週期內調用不執行。就好像你在淘寶搶購某一件限量熱賣商品時,你不斷點刷新點購買,但是總有一段時間你點上是沒有效果,這裏就用到了節流,就是怕點的太快致使系統出現bug。網絡
區別:在發生持續觸發事件時,防抖設置事件延遲並在空閒時間去觸發事件,而節流則是隔必定的時間觸發一次。閉包
二丶函數防抖app
函數防抖運用的實際場景有:實時搜索,拖拽,登陸用戶名密碼格式驗證等等。函數
實現函數防抖的關鍵就是對setTimeout()這個方法的運用。先以實時搜索爲例分析一下。性能
首先咱們要寫一個監聽函數用來監聽搜索框的value的變化。優化
var oInp;// 假設在此取得輸入框
oInp.oninput = ajax;
// 模擬ajax請求後臺數據
function ajax() {
console.log(this.value);// 搜索框value值
}
寫完以後咱們會發現每當咱們輸入一個單詞,即每當搜索框內容發生變化時都會觸發咱們的監聽函數來請求後臺數據,如此頻繁的請求確定不是咱們想要的,因此咱們就須要稍加處理一下,使其再也不一改變就觸發,而是當咱們輸完以後再觸發發送請求。針對這種需求咱們能夠使用防抖來實現。this
var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
clearTimeout(timer);
timer = setTimeout(function(){
ajax();
}, 1000);
};
// 模擬ajax請求後臺數據
function ajax() {
console.log(this.value);// 搜索框value值
}
這個總體的實現思想就是,當搜索框內容發生改變時,就會觸發一個定時器。可是當搜索框內容再次發生改變時,咱們先清除上一個定時器,再從新建立一個定時器。這樣,只有當咱們結束輸入,搜索框內容在必定時間內再也不發生改變時纔會發送請求。.net
可是上面的代碼塊還有兩個問題,一個就是this的指向,setTimeout()造成了一個閉包,當執行的時候,ajax()方法中的this實際指向window,因此咱們還須要進行如下優化,改變this指向。
var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
var _this = this;
clearTimeout(timer);
timer = setTimeout(function(){
ajax().apply(_this); // 綁定this
}, 1000);
};
// 模擬ajax請求後臺數據
function ajax() {
console.log(this.value);// 搜索框value值
}
第二個問題就是e -- 事件對象,在上面一系列的方法調用之中,e已經被丟了,變成了undefined,因此咱們還須要進行如下優化,將事件對象從新找回來。
var oInp;// 假設在此取得輸入框
var timer = null; // 定義一個全局定時器
oInp.oninput = function(e) {
var _this = this,
_arg = arguments; // e
clearTimeout(timer);
timer = setTimeout(function(){
ajax().apply(_this, _arg); // 綁定this, 傳入e
}, 1000);
};
// 模擬ajax請求後臺數據
function ajax(e) {
console.log(this.value);// 搜索框value值
console.log(e); // 事件對象
}
如上就基本實現了函數防抖。爲了實現通用性,在這裏將防抖封裝成一個方法,方便以後重複使用。
function debounce(handle, delay) {
var timer = null;
return function() {
var _this = this,
_arg = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
handle.apply(_this, _arg);
}, delay);
}
} // 其中 handle 爲須要進行防抖操做的函數,delay 爲延遲時間
三丶函數節流
函數節流運用的實際場景有:窗口調整,頁面滾動,搶購瘋狂點擊等等。
在這裏以瘋狂點擊爲例進行分析。
首先寫一個簡單的頁面,當點擊按鈕時,數字不斷增大,模擬搶購按鈕。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="show">0</div>
<button id="btn">點我</button>
<script>
var oDiv = document.getElementById('show'),
oBtn = document.getElementById('btn');
oBtn.onclick = function() {
oDiv.innerHTML = parseInt(oDiv.innerHTML) + 1;
}
</script>
</body>
</html>
咱們確定不但願用戶去瘋狂點擊致使數字不斷增長,甚至是使用惡意腳本去實現瘋狂點擊按鈕
for(var i = 0; i < 1000; i ++) {
oBtn.onclick();
}
因此就要引入一個新思想,那就是在一秒鐘以內不管用戶點多少次,都只算他點了一次,這就是節流的核心思想。
function throttle(handle, wait) {
var lasttime = 0;
return function(e) {
var nowtime = new Date().getTime();
if(nowtime - lasttime > wait) {
handle.apply(this, arguments);
lasttime = nowtime;
}
}
}
function buy() {
oDiv.innerHTML = parseInt(oDiv.innerHTML) + 1;
}
oBtn.onclick = throttle(buy, 1000);
如今分析一下throttle方法。
參數中 handle 爲須要進行節流的方法,wait爲等待時間。
由於咱們須要實如今必定的等待時間wait內不能執行buy()方法,因此首先須要兩個時間戳,一個記錄第一次點擊的時間lasttime,一個記錄當前的時間nowtime,只有當 nowtime 與 lasttime 的時間差大於wait時,纔會再次觸發buy(),同時改變lasttime爲新時間戳。
放在throttle()中就是首先記錄初始時間爲0,當第一次點擊時,得到如今時間爲nowtime,時間差大於wait,執行buy(),而後本次點擊的時間就成了一個新的時間點,下次點擊就須要和此次點擊的時間進行判斷,因此設置當前時間爲初始時間,而後下次點擊時繼續判斷。
四丶總結