實際上啊库倘,今天早上本來想干點別的,但是在吃早餐的時候瀏覽了下掘金,然后看到了這篇博文<a >Jake的關(guān)于圖片懶加載</a> 就順帶研究了一波函數(shù)節(jié)流和去抖動問題。
為什么要函數(shù)節(jié)流
以下場景往往由于事件頻繁被觸發(fā)庵朝,因而頻繁執(zhí)行DOM操作、資源加載等重行為又厉,導致UI停頓甚至瀏覽器崩潰九府。
- window對象的resize、scroll事件
- 拖拽時的mousemove事件
- 射擊游戲中的mousedown覆致、keydown事件
-
文字輸入侄旬、自動完成的keyup事件
例子以scroll事件進行解析
<code>
window.onscroll = function(){
lazyload();
//throttle(lazyload,window);
};
function lazyload(){
console.log("scroll執(zhí)行了"+scrollnum);
}
</code>
我們的本意只是讓鼠標滾動一次執(zhí)行一次滾動函數(shù),但是window的onscroll函數(shù)并不是等scroll結(jié)束之后才會調(diào)用煌妈,鼠標滾動或拖動滾動條儡羔,就會不停的觸發(fā)scroll事件宣羊,如果處理的東西多,低版本的IE也會陷入假死狀態(tài)汰蜘。
解決辦法
debounce
抖動:如果用手指一直按住一個彈簧仇冯,它將不會彈起直到你松手為止。 也就是說當調(diào)用動作n毫秒后,才會執(zhí)行該動作壮莹,若在這n毫秒內(nèi)又調(diào)用此動作則將重新計算執(zhí)行時間。這種比較適合window的resize事件,實際需求大多為停止改變大小n毫秒后執(zhí)行后續(xù)處理诵盼;而其他事件大多的需求是以一定的頻率執(zhí)行后續(xù)處理。針對這兩種需求就出現(xiàn)了和throttle兩種解決辦法扰肌。
-
去抖1
<code>
window.onscroll = function(){
//lazyload();
debounce(lazyload,window);
};
function debounce(method,context){
clearTimeout(method.timeout);
method.timeout = setTimeout(function(){
method.call(context);
},500);
}
function lazyload(){
console.log("scroll執(zhí)行了"+scrollnum);
}
</code>
效果如下丙猬,可以看出只執(zhí)行了一次lazyload函數(shù):
利用定時器,讓函數(shù)執(zhí)行延遲500毫秒项滑,在500毫秒內(nèi)如果有函數(shù)又被調(diào)用則刪除上一次調(diào)用依沮,這次調(diào)用500毫秒后執(zhí)行,如此往復
2.去抖2.
還有一種節(jié)流方式枪狂,是通過返回閉包的形式危喉,可以設(shè)置延遲時間,兩者運行的結(jié)果是一樣州疾,但是我在實際操作的時候設(shè)置延遲500時辜限,滾動過了一會才執(zhí)行了,設(shè)置為delay為100的時候在視覺上就沒有感覺延遲。而且函數(shù)也只滾動了一次严蓖。
<code>
function debounce1(method,delay){
var timer = null;
return function(){
var context = this,args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
method.apply(context,args);
},delay);
}
}
</code>
throttle
當我一直滾動鼠標的時候薄嫡,lazyload函數(shù)就會不斷被延遲,這樣只有停下來的時候才會執(zhí)行颗胡,那么再有些需要及時顯示的情況下毫深,就顯得不那么友好了(對于實現(xiàn)keyup事件的提示也沒有意義了),所以可以為函數(shù)添加一個參數(shù)作為到固定間隔必須執(zhí)行毒姨,到了這個時間間隔就必須執(zhí)行哑蔫,這個時候就引入了節(jié)流:
節(jié)流:如果將水龍頭擰緊直到水是以水滴的形式流出,那你會發(fā)現(xiàn)每隔一段時間弧呐,就會有一滴水流出闸迷。也就是會說預先設(shè)定一個執(zhí)行周期,當調(diào)用動作的時刻大于等于執(zhí)行周期則執(zhí)行該動作泉懦,然后進入下一個新周期
代碼如下:
<code>
function throttle2(method, delay, time) {
var timeout,startTime = new Date();
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果達到了規(guī)定的觸發(fā)時間間隔稿黍,觸發(fā) handler
if (curTime - startTime >= time) {
method.apply(context, args);
startTime = curTime;
// 沒達到觸發(fā)間隔,重新設(shè)定定時器
} else {
timeout = setTimeout(method, delay);
}
};
</code>
在這個函數(shù)中崩哩,當一次時間較長的時候還是會執(zhí)行兩次巡球,而不是等滾動停止之后再執(zhí)行言沐。達到了想要的效果,既沒有頻繁的執(zhí)行也沒有最后執(zhí)行
引一波圖片懶加載酣栈。
頁面加載速度影響最大的就是圖片险胰,一張普通的圖片可以達到幾M的大小,而代碼也許就只有幾十KB矿筝。當頁面圖片很多時起便,頁面的加載速度緩慢,幾S鐘內(nèi)頁面沒有加載完成窖维,也許會失去很多的用戶榆综。
所以,對于圖片過多的頁面铸史,為了加速頁面加載速度鼻疮,所以很多時候我們需要將頁面內(nèi)未出現(xiàn)在可視區(qū)域內(nèi)的圖片先不做加載, 等到滾動到可視區(qū)域后再去加載琳轿。這樣子對于頁面加載性能上會有很大的提升判沟,也提高了用戶體驗。
將頁面中的img標簽src指向一張小圖片或者src為空崭篡,然后定義data-src(這個屬性可以自定義命名挪哄,我才用data-src)屬性指向真實的圖片。src指向一張默認的圖片琉闪,否則當src為空時也會向服務器發(fā)送一次請求迹炼。可以指向loading的地址
只有當滾動到該圖片的時候才將該圖片的src換為data-src塘偎。這樣就能加速加載速度疗涉。
參考網(wǎng)址:https://gold.xitu.io/post/583b10640ce463006ba2a71a
http://www.cnblogs.com/dolphinX/p/3403821.html
http://blog.csdn.net/fengyinchao/article/details/50749317
https://segmentfault.com/a/1190000002764479
http://www.jb51.net/article/49502.htm
http://www.cnblogs.com/fsjohnhuang/p/4147810.html