[JS 성능 최적화] 함수 떨 기 (debounce) 와 함수 절 류 (throttle)

8558 단어
머리말
이것 은 흔히 말 하 는 화제 이다. 이 유 는 예전 에 전혀 신경 쓰 지 않 았 기 때문이다. 최근 에 직면 한 몇 가지 문 제 는 이 두 가지 작은 기 교 를 사용 해 야 하기 때문이다.둘째, 이 두 가지 기술 이 가 져 온 최적화 가 적지 않다.원인 셋 째 는 가방 을 닫 는 것 도 복습 하 는 김 에.
개발 중 에 당신 은 다음 과 같은 상황 을 만 날 수 있 습 니 다.
  • 감청 Window 대상 의 resize, scroll 사건
  • 드래그 시 감청 mousemove
  • 문 자 를 입력 할 때 입력 문자열 을 처리 합 니 다. 예 를 들 어 markdwonhtml
  • 로 변환 합 니 다.
  • 감청 파일 변화, 서비스 재 개
  • 첫 번 째 와 세 번 째 상황 은 사건 이 짧 은 시간 에 빈번하게 출발 하 는데 만약 에 사건 에서 대량의 계산 이 있 으 면 DOM, 자원 로드 등 무 거 운 행 위 를 자주 조작 하면 UI 가 멈 추고 심각 한 점 은 브 라 우 저 를 끊 게 할 수도 있다.네 번 째 상황 에 대해 서 는 편 집 된 파일 을 여러 번 Ctrl+S 누 르 는 것 을 좋아 하 는 개발 자 들 이 있 습 니 다. 빠 른 재 부팅 서 비 스 는 잡 을 수 있 지만 응용 프로그램 을 다시 시작 하면 불필요 한 재 부팅 을 여러 번 할 수 있 습 니 다.
    위의 일련의 수요 에 따라 debouncethrottle 두 가지 해결 방법 이 생 겼 다.
    함수 절 류
    함 수 는 한 주기 에 따라 실 행 됩 니 다. 예 를 들 어 window 에 하나의 resize 이 벤트 를 연결 한 후에 창 크기 가 바 뀌 면 1 을 인쇄 합 니 다. 함수 절 류 를 사용 하지 않 으 면 창 을 조절 할 때 콘 솔 이 계속 인쇄 1 하 는 것 을 발 견 했 습 니 다. 그러나 함수 절 류 를 사용 한 후에 우 리 는 조절 하 는 과정 에서 한 시간 간격 으로 인쇄 1 하 는 것 을 발견 할 수 있 습 니 다.
    함수 절 류 의 간단 한 실현:
    /**
    *
    * @param func    {Function}           
    * @param wait    {Number}         ,     (ms),  100ms
    *
    * @return        {Function}       “  ”  
    */
    
    function throttle(func, wait = 100) {
       //                 
       let timer = null;
       let previous; //       
       return function() {
           //               ,    fn
           const context = this;
           const args = arguments;
           const now = +new Date();
           if (previous && now < previous + wait) { //     
               clearTimeout(timer);
       	    timer = setTimeout(function() {
       	        previous = now;
       	        func.apply(context, args);
       	    }, wait);
           } else {
               previous = now;
               func.apply(context, args);
           }
       };
    }
    

    사용 하 는 방법 도 간단 하 다.
    const btn = document.getElementById('btn');
    
    function demo() {
       console.log('click');
    }
    btn.addEventListener('click', throttle(demo, 1000));
    

    React 에서 어떻게 사용 하 는 지 보 세 요. 아래 감청 창 resize 과 입력 상자 onChange 이벤트:
    import React, { Component } from 'react';
    import { throttle } from '../../utils/utils';
    
    export default class Demo extends Component {
     constructor() {
       super();
       this.change = throttle((e) => {
           console.log(e.target.value);
           console.log('throttle');
       }, 100);
     }
     
     componentDidMount() {
       window.addEventListener('resize', throttle(this.onWindowResize, 60));
     }
     
      componentWillUnmount() {
       window.removeEventListener('resize', throttle(this.onWindowResize, 60));
     }
     
     onWindowResize = () => {
     	console.log('resize');
     }
    
     handleChange = (e) => {
       e.persist();
       this.change(e);
     }
    
     render() {
       return (
           <input
             onChange={this.handleChange}
           />
       );
     }
    }
    

    함수 떨 기
    이벤트 가 실 행 된 후에 특정한 시간 (N) 을 기 다 려 야 리 셋 함수 가 실 행 됩 니 다. 만약 에 다시 기다 리 는 시간 안에 이벤트 가 실 행 될 경우 다시 시간 N 을 기 다 려 야 합 니 다. 이벤트 N 내 이벤트 가 실 행 될 때 까지 마지막 으로 이벤트 N 을 터치 한 후에 실행 함 수 를 실행 합 니 다.
    아니면 창 resize 인지, 창 크기 를 계속 바 꾸 면 1 을 인쇄 하지 않 고, 창 크기 변경 을 중단 하고 일정 시간 을 기 다 려 야 1 을 인쇄 할 수 있 습 니 다.
    함수 떨 기 간단 실현:
    /**
     * @param     func     {Function}           
     * @param     delay    {Number}         ,     (ms)
     * @return    {Function}
     */
    
    function debounce(fn, delay = 1000) {
      let timer;
    
      //       ,                 delay       func   
      return function () { 
    
        //               ,   func
        var context = this
        var args = arguments
    
        //      ,     
        clearTimeout(timer)
    
        //               (               ),
        //    delay       func
        timer = setTimeout(function () {
          fn.apply(context, args);
        }, delay);
      }
    }
    

    장면 을 사용 하고 파일 의 변 화 를 감청 하 며 응용 을 다시 시작 합 니 다.
    const debounce = require('./debounce');
    
    watcher.on('change', debounce(() => {
        const child = spawn('npm', ['run', 'dev:electron'], {
          cwd,
          detached: true,
          stdio: 'inherit'
        })
        child.unref();
        electron.app.quit();
      }, delay));
    

    좋은 웹페이지 즐겨찾기