Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

节流,防抖,wait-promise 与异步 Timer #15

Open
WangShuXian6 opened this issue May 19, 2018 · 9 comments
Open

节流,防抖,wait-promise 与异步 Timer #15

WangShuXian6 opened this issue May 19, 2018 · 9 comments
Labels
util 工具

Comments

@WangShuXian6
Copy link
Owner

WangShuXian6 commented May 19, 2018

throttle 和 debounce

节流:设定一个时间间隔,某个频繁触发的函数,在这个时间间隔内只会执行一次。也就是说,这个频繁触发的函数会以一个固定的周期执行。

节流函数,只允许一个函数在 X 毫秒内执行一次

与防抖相比,节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件 handler。

防抖:设定一个时间间隔,当某个频繁触发的函数执行一次后,在这个时间间隔内不会再次被触发,如果在此期间尝试触发这个函数,则时间间隔会重新开始计算。

防抖函数:防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。

https://github.com/akira-cn/wait-promise
https://www.h5jun.com/post/wait-promise.html

npm install wait-promise

import wait from 'wait-promise'

 let a=1

      setInterval(()=>{
        a++
        //console.log('a----',a)
      },2000)

      console.log('await开始--------')

      console.log(wait)

      await wait.before(20000).until(()=>{
        if(a>18){
          console.log('a>18',a)
          return true
        }else{
          console.log('a<18',a)
          return false
        }
      }).then(()=>{
        console.log('成功')
        console.log('结束--------')
      }).catch(()=>{
        console.log('失败')
        console.log('结束--------')
      })
    }
//失败
let a=1

      setInterval(()=>{
        //a++
        //console.log('a----',a)
      },2000)

      console.log('await开始--------')

      console.log(wait)

      await wait.before(5000).until(()=>{
        setTimeout(()=>{
          a=19
        },4000)
        if(a>18){
          console.log('a>18',a)
          return true
        }else{
          console.log('a=<18',a)
          return false
        }
      }).then(()=>{
        console.log('成功')
        console.log('结束--------')
      }).catch(()=>{
        console.log('失败')
        console.log('结束--------')
      })
    }
@WangShuXian6 WangShuXian6 changed the title wait-promise 与异步异步 Timer wait-promise 与异步 Timer May 19, 2018
@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented May 19, 2018

异步轮询

await this.asyncPollingPayResult()

//  开始轮询支付状态
    async asyncPollingPayResult() {
      let startFlag = 1
      let timer = setInterval(() => {
        startFlag++
        if (startFlag > 15 || this.isPaySuccess === true) {
          clearInterval(timer)
        } else {
          this.pollingReauestPayResult()
        }
      }, 2000)

      await wait.before(30000).until(() => {
        if (this.isPaySuccess === true) {
          // 清空购物车
          this.clearNewOrder()
          return true
        } else {
          return false
        }
      }).then(() => {
        // 30秒内收到成功结果
      }).catch(() => {
        // 30秒内未收到成功的结果或收到失败的结果
        this.showMessage('服务器忙,请联系前台')
      })
    }


//  微信付款后轮询支付状态是否成功
    pollingReauestPayResult() {
      wepy.request({
        url: pollingPayResultApi,
        method: 'POST',
        header: {
          'Content-Type': 'Application/json;charset=UTF-8'
        },
        data: {}
      }).then((response) => {
        console.log(response)
        this.checkPayResult(response.data)
      }).catch((error) => {
        wepy.showToast({
          title: '服务器忙!',
        })
        return false
      })
    }

//  判断轮询结果
    checkPayResult(data) {
      if (data.return_code === undefined ||
          data.return_code === 'FAIL') {
        console.log('支付成功后拉取状态:失败:', data)
        return false
      } else if (data.return_code === 'SUCCESS') {
        this.methods.updateSettleOrder(data.order)
        this.isPaySuccess = true
        this.$apply()
      }
    }

@WangShuXian6 WangShuXian6 changed the title wait-promise 与异步 Timer 节流,防抖,wait-promise 与异步 Timer May 31, 2018
@WangShuXian6
Copy link
Owner Author

throttle 节流

https://gist.github.com/beaucharman/e46b8e4d03ef30480d7f4db5a78498ca

function throttle(callback, wait, context = this) {
  let timeout = null 
  let callbackArgs = null
  
  const later = () => {
    callback.apply(context, callbackArgs)
    timeout = null
  }
  
  return function() {
    if (!timeout) {
      callbackArgs = arguments
      timeout = setTimeout(later, wait)
    }
  }
}

/**
 * Normal event
 * event      | |      |
 * time     ----------------
 * callback   | |      |
 * 
 * Call search at most once per 300ms while keydown
 * keydown     | |     |  |
 * time     -----------------
 * search          |       | 
 *             |300|   |300|
 */
 
/** usage
const handleKeydown = throttle((e) => {
  console.log(e.target.value)
}, 300)
input.addEventListener('keydown', handleKeydown)
*/

@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented May 31, 2018

debounce 防抖

https://gist.github.com/beaucharman/1f93fdd7c72860736643d1ab274fee1a

function debounce(callback, wait, context = this) {
  let timeout = null 
  let callbackArgs = null
  
  const later = () => callback.apply(context, callbackArgs)
  
  return function() {
    callbackArgs = arguments
    clearTimeout(timeout)
    timeout = setTimeout(later, wait)
  }
}

/** 
 * Normal event
 * event      | |      |
 * time     ----------------
 * callback   | |      |
 *
 * Call log only when it's been 100ms since the last sroll
 * scroll     | |      |
 * time     ----------------
 * callback         |      | 
 *              |100|  |100|
 */

/* usage
const handleScroll = debounce((e) => {
  console.log('Window scrolled.')
}, 100)
window.addEventListener('scroll', handleScroll)
*/

@WangShuXian6
Copy link
Owner Author

es6-promise-debounce

https://www.npmjs.com/package/es6-promise-debounce

@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented May 31, 2018

带触发边界的 throttle 节流

/**
 * 频率控制 返回函数连续调用时,func 执行频率限定为 次 / wait
 * 
 * @param  {function}   func      传入函数
 * @param  {number}     wait      表示时间窗口的间隔
 * @param  {object}     options   如果想忽略开始边界上的调用,传入{leading: false}。
 *                                如果想忽略结尾边界上的调用,传入{trailing: false}
 * @return {function}             返回客户调用函数   
 */
_.throttle = function(func, wait, options) {
let context, args, result
    let timeout = null
    // 上次执行时间点
    let previous = 0
    if (!options) options = {}
    // 延迟执行函数
    let later = function() {
      // 若设定了开始边界不执行选项,上次执行时间始终为0
      previous = options.leading === false ? 0 : new Date().getDate()
      timeout = null
      result = func.apply(context, args)
      if (!timeout) context = args = null
    };
    return function() {
      let now = new Date().getDate()
      // 首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。
      if (!previous && options.leading === false) previous = now
      // 延迟执行时间间隔
      let remaining = wait - (now - previous)
      context = this
      args = arguments
      // 延迟时间间隔remaining小于等于0,表示上次执行至此所间隔时间已经超过一个时间窗口
      // remaining大于时间窗口wait,表示客户端系统时间被调整过
      if (remaining <= 0 || remaining > wait) {
        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
    }
}

@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented May 31, 2018

带触发边界的 debounce 防抖

/**
 * 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
 *
 * @param  {function} func        传入函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时,调用触发于开始边界而不是结束边界
 * @return {function}             返回客户调用函数
 */
const _.debounce = function(func, wait, immediate) {
  let timeout, args, context, timestamp, result

    let later = function() {
      // 据上一次触发时间间隔
      let last = new Date().getDate() - timestamp

      // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
      if (last < wait && last > 0) {
        timeout = setTimeout(later, wait - last)
      } else {
        timeout = null
        // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
        if (!immediate) {
          result = func.apply(context, args)
          if (!timeout) context = args = null
        }
      }
    }

    return function() {
      context = this
      args = arguments
      timestamp = new Date().getDate()
      let callNow = immediate && !timeout
      // 如果延时不存在,重新设定延时
      if (!timeout) timeout = setTimeout(later, wait)
      if (callNow) {
        result = func.apply(context, args)
        context = args = null
      }

      return result
    }
}

@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented Apr 19, 2019

防抖 装饰器工厂 @debounce

export function debounce(timeout) {
  const instanceMap = new Map(); // 创建一个Map的数据结构,将实例化对象作为key
  return function (target, key, descriptor) {
    return Object.assign({}, descriptor, {
      value: function value() {
// 清除延时器
        clearTimeout(instanceMap.get(this));
        // 设置延时器
        instanceMap.set(this, setTimeout(() => {
          // 调用该方法
          descriptor.value.apply(this, arguments);
          // 将延时器设置为 null
          instanceMap.set(this, null);
        }, timeout));
      }
    })
  }
}

使用

class Test {

   @debounce(600)
  onNext() {
    console.log('click')
  
  }
}

@WangShuXian6
Copy link
Owner Author

WangShuXian6 commented May 14, 2019

节流 装饰器工厂 @Throttle

限制时间内只会执行一次,并且立刻执行

export function throttle(time) {
  //let flag = false
  const instanceMap = new Map(); // 创建一个Map的数据结构,将实例化对象作为key
  return function (target, key, descriptor) {
    return Object.assign({}, descriptor, {
      value: function value() {
        //if (flag) return
        if (instanceMap.get(this)) return
        descriptor.value.apply(this, arguments);
        instanceMap.set(this, true)
        //flag = true
        setTimeout(() => {
          //flag = false
          instanceMap.set(this, null)
        }, time)
      }
    })
  }
}

使用

class Test {

   @throttle(600)
  onNext() {
    console.log('click')
  
  }
}

@WangShuXian6 WangShuXian6 added the util 工具 label Jun 26, 2019
@WangShuXian6
Copy link
Owner Author

函数节流 Throttle

export const throttle = (func, wait) => {
  const instanceMap = new Map();

  return function() {
    if (instanceMap.get(this)) return;
    func.apply(this, arguments);
    instanceMap.set(this, true);
    setTimeout(() => {
      instanceMap.set(this, null);
    }, wait);
  };
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
util 工具
Projects
None yet
Development

No branches or pull requests

1 participant