JavaScript 성능 최적화: 함수 조절(throttle) 및 함수 디바운스(debounce)

高洛峰
풀어 주다: 2016-12-29 10:08:36
원래의
1431명이 탐색했습니다.

함수 조절이란 간단히 말해서 짧은 시간 간격 내에 함수를 계속해서 호출할 수 없다는 의미입니다. 마지막 함수 실행 이후 지정한 시간 간격이 경과한 경우에만 다음 함수 호출이 가능합니다.

기능 조절의 원리는 꽤 간단하다고 다들 생각해 보셨을 텐데요, 바로 타이머입니다. 시간을 트리거할 때 먼저 setTimeout을 사용하여 이벤트를 잠시 지연시킨 다음 실행합니다. 이 시간 간격 내에 이벤트가 다시 트리거되면 원래 타이머를 지우고 잠시 동안 실행을 지연하기 위해 새 타이머를 setTimeout합니다. .그게 다야.

다음 시나리오는 빈번한 이벤트로 인해 발생하는 경우가 많으므로 DOM 작업, 리소스 로딩 및 기타 과도한 활동이 자주 수행되어 UI가 일시 중지되거나 브라우저가 충돌할 수도 있습니다.

1. 창 개체의 크기 조정 및 스크롤 이벤트

2. 슈팅 게임에서 마우스 이동 이벤트

3. mousedown, keydown 이벤트

4. 텍스트 입력, 자동 완료 키업 이벤트

실제로 창 크기 조정 이벤트의 경우 실제 요구 사항은 대부분 크기 n 변경을 중지하는 것입니다. 밀리초 후 후속 처리를 수행합니다. 반면 대부분의 다른 이벤트는 특정 빈도로 후속 처리를 수행해야 합니다. 이러한 두 가지 요구에 부응하여 디바운스와 스로틀이라는 두 가지 솔루션이 등장했습니다.

스로틀과 디바운스는 요청과 응답 속도 불일치 문제를 해결하는 두 가지 솔루션입니다. 둘 사이의 차이점은 서로 다른 전략을 선택하는 데 있습니다.

throttle 동일한 시간 간격으로 기능을 실행합니다.

debounce 시간 간격 t 내에 이벤트가 다시 발생하면 시간이 다시 시작되고 중지 시간이 t 이상이 될 때까지 함수가 실행되지 않습니다.

1. 스로틀 기능 간단 구현

function throttle(fn, threshhold, scope) { 
threshhold || (threshhold = 250); 
var last, 
timer; return function () { 
var context = scope || this; 
var now = +new Date(), 
args = arguments; 
if (last && now - last + threshhold < 0) { 
// hold on to it 
clearTimeout(deferTimer); 
timer = setTimeout(function () { 
last = now; 
fn.apply(context, args); 
}, threshhold); 
} else { 
last = now; 
fn.apply(context, args); 
} 
};}
로그인 후 복사

콜 방식

$(&#39;body&#39;).on(&#39;mousemove&#39;, throttle(function (event) 
{
console.log(&#39;tick&#39;);
}, 1000));
로그인 후 복사

디바운스 기능 간단 구현

function debounce(fn, delay) 
{ 
var timer = null; 
return function () 
{ 
var context = this,
args = arguments; 
clearTimeout(timer); 
timer = setTimeout(function () { 
fn.apply(context, args); 
}, delay); 
};}
로그인 후 복사

호출 방법

$(&#39;input.username&#39;).keypress(debounce(function (event)
{
// do the Ajax request
}, 250));
로그인 후 복사

3. 간단한 캡슐화 구현

/** * throttle * @param fn, wait, debounce */var throttle = function ( fn, wait, debounce ) { 
var timer = null, // 定时器 
t_last = null, // 上次设置的时间 
context, // 上下文 
args, // 参数 
diff; // 时间差 
return funciton () { 
var curr = + new Date(); 
var context = this, args = arguments; 
clearTimeout( timer ); 
if ( debounce ) { // 如果是debounce 
timer = setTimeout( function () { 
fn.apply( context, args ); 
}, wait ); 
} else { // 如果是throttle 
if ( !t_last ) t_last = curr; 
if ( curr - t_last >= wait ) { 
fn.apply( context, wait ); 
context = wait = null; 
} 
} }}/** * debounce * @param fn, wait */var debounce = function ( fn, wait ) 
{ 
return throttle( fn, wait, true );
}
로그인 후 복사

요약: 이 두 가지 방법은 mousemove, keydown, keyup , 키 누르기, 스크롤 등
네이티브 이벤트를 제어하지 않고 바인딩만 하면 브라우저가 정지되고 사용자 경험이 저하됩니다. js 성능을 향상시키기 위해서는 위와 유사한 이벤트를 사용할 때 함수 조절이나 함수 디바운스를 사용하여 제어하는 ​​것이 좋습니다.

4. Underscore v1.7.0 관련 소스코드 분석

1. _.throttle 기능

_.throttle = function(func, wait, options) { 
var context, args, result; 
var timeout = null; 
// 定时器 
var previous = 0; 
// 上次触发的时间 
if (!options) options = {}; 
var later = function() { 
previous = options.leading === false ? 0 : _.now(); 
timeout = null; 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
}; 
return function()
{ 
var now = _.now(); 
// 第一次是否执行 
if (!previous && options.leading === false) previous = now; 
// 这里引入了一个remaining的概念:还剩多长时间执行事件 
var remaining = wait - (now - previous); 
context = this; 
args = arguments; 
// remaining <= 0 考虑到事件停止后重新触发或者 
// 正好相差wait的时候,这些情况下,会立即触发事件 
// remaining > wait 没有考虑到相应场景 
// 因为now-previous永远都是正值,且不为0,那么 
// remaining就会一直比wait小,没有大于wait的情况 
// 估计是保险起见吧,这种情况也是立即执行 
if (remaining <= 0 || remaining > wait) 
{ 
if (timeout)
{ 
clearTimeout(timeout); 
timeout = null; 
} 
previous = now; 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
// 是否跟踪 
} else if (!timeout && options.trailing !== false)
{ 
timeout = setTimeout(later, remaining); 
} 
return result; 
};};
로그인 후 복사

에서 알 수 있듯이 위에서 밑줄은 더 일반적인 상황을 고려합니다: options.leading:

처음 실행할지 여부 기본값은 true입니다. 이는 처음으로 실행된다는 의미입니다. {leading:false를 전달합니다. } 옵션의 첫 번째 실행을 비활성화합니다. trailing: 마지막으로 실행할지 여부, 기본값은 true입니다. 이는 마지막으로 실행된다는 의미입니다. {trailing: false}를 전달하면 마지막으로 실행되지 않는다는 의미입니다. 최초 실행 여부는 이벤트가 처음 트리거될 때 먼저 이벤트를 트리거할지 여부를 의미합니다. 필요한 경우 이전=0이고 나머지가 음수 값이면 함수가 즉시 호출됩니다. 소위 마지막 실행 여부는 이벤트가 끝난 후 이 메서드가 마지막으로 실행되는 시간입니다. 실행하려면 타이머를 설정합니다. 즉, 이벤트가 끝난 후 실행됩니다. remianing > wait는 클라이언트 시간이 수정되었음을 나타냅니다.

2._.debounce 함수

_.debounce = function(func, wait, immediate) { 
// immediate默认为false 
var timeout, args, context, timestamp, result; 
var later = function() { 
// 当wait指定的时间间隔期间多次调用_.debounce返回的函数,则会不断更新timestamp的值,导致last < wait && last >= 0一直为true,从而不断启动新的计时器延时执行func var last = _.now() - timestamp; 
if (last < wait && last >= 0) { 
timeout = setTimeout(later, wait - last); 
} else { 
timeout = null; 
if (!immediate) { 
result = func.apply(context, args); 
if (!timeout) context = args = null; 
} 
} 
}; 
return function() 
{ 
context = this; 
args = arguments; 
timestamp = _.now(); 
// 第一次调用该方法时,且immediate为true,则调用func函数 
var callNow = immediate && !timeout; // 在wait指定的时间间隔内首次调用该方法,则启动计时器定时调用func函数 
if (!timeout) timeout = setTimeout(later, wait); 
if (callNow) { 
result = func.apply(context, args); 
context = args = null; 
} 
return result; 
};};
로그인 후 복사

_.debounce의 좋은 점은 func 함수 호출의 지연을 cleanTimeout을 호출하여 조정하는 대신 재귀적으로 시작한다는 것입니다. 구현하다.

위 내용은 에디터가 JavaScript 성능 최적화를 위해 소개한 Throttling 및 Debounce 기능입니다. 궁금한 점이 있으면 에디터에게 메시지를 남겨주세요. 제 시간에 모든 사람에게 답장을 보내드립니다. 또한 PHP 중국어 웹사이트를 지원해 주신 모든 분들께 감사드립니다!

자바스크립트 성능 최적화 기능 조절(throttle)과 기능 디바운스(debounce)에 관련된 더 많은 글은 PHP 중국어 홈페이지를 주목해주세요!


원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!