Vue - Lodash を使用したデバウンスとスロットリング

GitHub デモアドレス

オンライン プレビュー

ロダッシュ公式サイト

参考:

Vue のアンチシェイクとスロットリングの詳細な紹介
Vue はアンチシェイク
とアンチシェイクとスロットリングの紹介jsのアンチシェイクとスロットリングの
実現原理と適用シナリオ

アンチシェイクとスロットリングとは何ですか?

機能のスロットリング (throttle) と機能の anti-shake (debounce) はどちらも、機能の実行頻度を制限し、機能の高いトリガー周波数によって引き起こされる応答速度を最適化し、トリガー周波数に追いつくことができず、遅延し、中断されたアニメーションまたはフリーズ
. 頻繁にイベントをトリガーするための最適化スキーム。

手ぶれ防止(デバウンス)

アンチシェイクは、揺れを防ぎ、イベントの繰り返しトリガーを回避することです。
アンチシェイクは、高頻度イベントがトリガーされた後、n 秒以内に 1 回だけ機能が実行され、高頻度イベントが n 秒以内に再度トリガーされると、時間が再計算されるというものです。
n 秒後にイベントを実行. n 秒後に繰り返しトリガーされた場合, タイミングが再開されます.
簡単に言えば, イベントが連続して複数回トリガーされた場合, 最後のイベントのみが実行されます.

  • 実装方法:イベントがトリガーされるたびに遅延呼び出しメソッドを設定し、以前の遅延呼び出しメソッドをキャンセルします
  • 指定された時間間隔内にイベントが継続的にトリガーされる場合、呼び出しメソッドは継続的に遅延されます

使用シーン

  • input 検索入力、ユーザーは連続して値を入力します
  • ウィンドウはサイズ変更イベントをトリガーします
  • mousemove マウススライドイベント
  • スクロール スクロール バーのスライド リクエストをスクロールし、さらに読み込むにはプルアップおよびボトムアウトします
  • フォーム検証、ボタン送信イベント

スロットル

スロットリングとは、トラフィックを減らし、頻繁にトリガーされるイベントを減らし、それらを定期的に実行することです。イベントが発生する頻度を制御します。そのため、スロットリングは関数の実行頻度を低下させます。
n 秒以内に 1 回だけ実行され、n 秒以内に繰り返しトリガーされた場合、1 回だけ有効になります。
立て続けに複数回トリガーされた場合、指定された時間内に 1 回だけトリガーされます。1 秒に制限されている場合は、1 秒以内に 1 回だけ実行され、何があっても対応する操作は 1 秒以内に実行されます。

  • 実装方法:イベントがトリガーされるたびに、現在実行待ちの遅延関数がある場合は、すぐに戻ります
  • 指定された時間間隔内でイベントが連続してトリガーされる場合、呼び出し元のメソッドは指定された時間間隔内で 1 回実行されます。

使用シーン

  • 確認コードを取得する
  • マウスが連続してクリックされてトリガー、mousedown (指定された時間内に 1 回だけトリガー)
  • mousemove マウススライドイベント
  • スクロールバーのスライドリクエスト、プルアップとボトムアウトでさらにロード
  • 検索、送信などのボタン機能

安定化とスロットリングの違い:

同じ点:

  • どちらも setTimeout を使用して実現できます
  • 目的は、コールバック関数の実行頻度を減らし、計算リソースを節約することです

違い:

  • 手ぶれ防止とは、clearTimout と setTimeout を使用して一定期間の連続操作後にコールバックを処理することです。

  • スロットリングは、一定期間に 1 回だけ実行される継続的な操作であり、パフォーマンスを向上させるために頻度の高いイベントで使用されます。

  • アンチシェイクは、サーバー上の動的検索結果に対するユーザー入力コンテンツなど、予測できないユーザーのアクティブな動作に使用されます。ユーザーのタイピング速度は予測不能で不規則です。

  • スロットリングは、ユーザーが製品ウィンドウをスライドさせたときに埋められたポイント要求を送信するなど、一部の非ユーザー アクティブな動作または予測可能なユーザー アクティブな動作に使用できます。固定高さのスライドは既知のロジックであり、規則性があります。

  • 手ぶれ補正は最後のイベント トリガーに焦点を合わせ、スロットリングは指定された時間内に 1 回だけ実行されます。

  • アンチシェイクは複数の実行を最後の実行にすることであり、スロットリングは複数の実行を間隔をあけて実行することです

手ぶれ防止とスロットリングのユーティリティ

/**
 * 防抖  (传入所要防抖的方法/回调与延迟时间)
 * @param {Function} func
 * @param {number} delay
 * @return {*}
 */
export function debounce2(func, delay) {
    
    
  let timer = null
  // 借助闭包,使得变量timer不被回收
  return function() {
    
    
    // 保存当前环境下的实例对象,this即为引入该方法的那个组件实例对象
    const th = this
    // 保存传入参数
    const args = arguments
    // 第一次timer为null,跳过该判断,执行setTimeout()
    if (timer) {
    
    
      // 之后如果timer存在,则把上一次的销毁,也就是setTimeout(),则里面的函数执行也会抛弃
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
    
    
      // apply(),改变this指向,指向正在操作的组件实例,传入参数
      func.apply(th, args)
      timer = null
    }, delay)
  }
}

/*
  由于使用闭包,使得timer不被回收,在A组件中每次调用该方法时会去判断timer是否存在,如果存在,
  表示上一次输入在等待执行fn(),期间如果继续输入,且在1s内,则会把上一次未执行的(setTimeout中的)fn()销毁,
  重新定时1s,以此来达到输入结束过1s才执行fn(),即触发事件或者发送请求。
*/

/**
 * 节流  (传入所要节流的方法/回调与延迟时间)
 * @param {Function} func
 * @param {number} delay
 * @return {*}
 */
export function throttle(func, delay) {
    
    
  let flag = true
  return function() {
    
    
    const th = this
    const args = arguments
    if (!flag) {
    
    
      // 未超过时间间隔,flag无效,不执行fn
      return false
    }
    func.apply(th, args)
    flag = false // 在时间间隔内把状态位flag设为无效(false)
    setTimeout(() => {
    
    
      flag = true // 超过时间间隔把状态位flag设为有效(true)
    }, delay)
  }
}

ロダッシュのインストール

ブラウザ環境:

<script src="lodash.js"></script>

npm経由:

$ npm i -g npm
$ npm i --save lodash

Lodash デバウンス関数のdebouncedドキュメント
Lodash スロットリング関数のthrottleドキュメント

Lodash を使用したアンチシェイクとスロットリング

未処理の場合、入力テキストが変更されたときにイベントがトリガーされるか、クリックされるとイベントがトリガーされます

ここに画像の説明を挿入

処理後、
テキスト入力に使用されるアンチシェイク、設定された間隔 0.5 秒、複数のクリックは最後にのみトリガーされますクエリ ボタンをクリックして使用されるスロットリング、設定された間隔 3 秒のみがトリガーされ
ます複数回のクリック後、3 秒以内に 1 回

ここに画像の説明を挿入

防振キーコード

 <el-input v-model="queryParams2.name" maxlength="20" placeholder="请输入" 
 clearable @input="onChange2" @keyup.enter.native="onSearch2" />

// lodash文档: https://www.lodashjs.com/
//
// 搜索框防抖 - lodash实现
// 不要在debounce里写箭头函数,否则this的指向就是undefined,而不是Vue实例对象。
// 注意这里若是使用箭头函数的话, this为 undefined https://github.com/vue-styleguidist/vue-docgen-api/issues/23
onChange2: lodash.debounce(function() {
    
    
  // Do some things
  this.getListByKeyword()
}, 500),
getListByKeyword() {
    
    
  // 请求...
  console.log('根据关键字 请求...')
  console.log(this.queryParams2.name)
  console.log(JSON.stringify(this.queryParams2))
},

スロットリング キー コード - 方法 1

<el-button class="spp-form-btn" size="small" type="primary" @click="onSearch2()">查询</el-button>

 // 按钮节流 - lodash实现 - 方式1
 onSearch2: lodash.throttle(function() {
    
    
   // Do some things
   this.requestList()
 }, 3000),
 requestList() {
    
    
   // 请求...
   console.log('点击搜索按钮 请求...')
   console.log(JSON.stringify(this.queryParams2))
 },

スロットリング キー コード - モード 2

 <el-button class="spp-form-btn" size="small" type="primary" style="width: 120px;" 
 @click="onSearch22()">查询(方式2</el-button>

created() {
    
    
  // 按钮节流 - lodash实现 - 方式2
  this.onSearch22 = lodash.throttle(this.onSearch22, 3000)
},

requestList() {
    
    
  // 请求...
  console.log('点击搜索按钮 请求...')
  console.log(JSON.stringify(this.queryParams2))
},
// 按钮节流 - lodash实现 - 方式2
onSearch22() {
    
    
  // Do some things
  this.requestList3()
},

すべてのコード

<template>

  <div class="spp-theme-body spp-theme-pad">
  
    <h1 style="margin:10px 0px 30px;">防抖与节流</h1>
    
    <div> 未处理前 </div>
    <el-form :inline="true" size="small" :model="queryParams" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams.name" maxlength="20" placeholder="请输入" clearable @input="onChange" @keyup.enter.native="onSearch" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch()">查询</el-button>
      </el-form-item>
    </el-form>

    <div class="spp-theme-top"> lodash实现 - 搜索框防抖(0.5秒) / 点击按钮节流(3秒内) </div>
    <el-form :inline="true" size="small" :model="queryParams2" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams2.name" maxlength="20" placeholder="请输入" clearable @input="onChange2" @keyup.enter.native="onSearch2" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch2()">查询</el-button>
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" style="width: 120px;" @click="onSearch22()">查询(方式2</el-button>
      </el-form-item>
    </el-form>

    <div class="spp-theme-top"> utils实现 - 搜索框防抖(0.5秒) / 点击按钮节流(3秒内) </div>
    <el-form :inline="true" size="small" :model="queryParams2" class="spp-form-search spp-theme-top">
      <el-form-item>
        <span class="spp-form-label" style="width:80px">
          <i class="icon" /><i class="label">名称:</i>
        </span>
        <el-input v-model="queryParams3.name" maxlength="20" placeholder="请输入" clearable @input="onChange3" @keyup.enter.native="onSearch3" />
      </el-form-item>
      <el-form-item>
        <el-button class="spp-form-btn" size="small" type="primary" @click="onSearch3()">查询</el-button>
      </el-form-item>
    </el-form>

  </div>

</template>

<script>
import lodash from 'lodash'
import {
    
     debounce2, throttle } from '@/utils/index'

export default {
    
    
  components: {
    
    },
  data() {
    
    
    return {
    
    
      tableHeight: 170,
      tableLoading: false,
      tableData: [],
      queryParams: {
    
    
        name: '',
        page: 1,
        limit: this.pageGroup.size
      },
      queryParams2: {
    
    
        name: '',
        page: 1,
        limit: this.pageGroup.size
      },
      queryParams3: {
    
    
        name: '',
        page: 1,
        limit: this.pageGroup.size
      }
    }
  },
  created() {
    
    
    // 按钮节流 - lodash实现 - 方式2
    this.onSearch22 = lodash.throttle(this.onSearch22, 3000)
  },
  mounted() {
    
    },
  methods: {
    
    
    onChange(val) {
    
    
      console.log(val)
    },
    onSearch() {
    
    
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams))
    },
    // lodash文档: https://www.lodashjs.com/
    //
    // 搜索框防抖 - lodash实现
    // 不要在debounce里写箭头函数,否则this的指向就是undefined,而不是Vue实例对象。
    // 注意这里若是使用箭头函数的话, this为 undefined https://github.com/vue-styleguidist/vue-docgen-api/issues/23
    onChange2: lodash.debounce(function() {
    
    
      // Do some things
      this.getListByKeyword()
    }, 500),
    getListByKeyword() {
    
    
      // 请求...
      console.log('根据关键字 请求...')
      console.log(this.queryParams2.name)
      console.log(JSON.stringify(this.queryParams2))
    },
    // 按钮节流 - lodash实现 - 方式1
    onSearch2: lodash.throttle(function() {
    
    
      // Do some things
      this.requestList()
    }, 3000),
    requestList() {
    
    
      // 请求...
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams2))
    },
    // 按钮节流 - lodash实现 - 方式2
    onSearch22() {
    
    
      // Do some things
      this.requestList3()
    },
    // 防抖
    // 项目工具类
    // 如果需要加参数,则在function空的形参列表里加入
    onChange3: debounce2(function(val) {
    
    
      console.log('录入的文字', val)
      // Do some things
      this.getListByKeyword3()
    }, 500),
    getListByKeyword3() {
    
    
      // 请求...
      console.log('根据关键字 请求...')
      console.log(this.queryParams3.name)
      console.log(JSON.stringify(this.queryParams3))
    },
    onSearch3: throttle(function() {
    
    
      // Do some things
      this.requestList3()
    }, 3000),
    requestList3() {
    
    
      // 请求...
      console.log('点击搜索按钮 请求...')
      console.log(JSON.stringify(this.queryParams3))
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .el-input__icon:after {
    
    
  height: auto;
}
</style>

おすすめ

転載: blog.csdn.net/iotjin/article/details/128938355