Vue のスロットリング関数使用時の落とし穴ガイド

Vue のスロットリング関数使用時の落とし穴ガイド

序文

一般的なビジネス シナリオでは、検索ボックスへの入力が完了した後、検索データを取得するために関連リクエストを送信する必要があります。頻繁にイベントがトリガーされると、インターフェース要求が頻繁に発生しすぎます。したがって、リソースの無駄を避けるために、不必要なリクエストを禁止するようにこれを制限する必要があります〜

ビジネスシナリオを例に挙げましょう

コンセプト:

手ぶれ補正機能の紹介

addEventListenerについて

使用例:

    関数デバウンス(fn) {
        let timeout = null; // タイマーの戻り値を格納するマーカーを作成する return function () {
            clearTimeout(timeout); // ユーザーが入力するたびに、以前のsetTimeoutをクリアします。timeout = setTimeout(() => {
                // 次に、新しい setTimeout を作成します。これにより、入力文字の後の間隔内にさらに入力があった場合、fn 関数は実行されません。fn.apply(this, arguments);
            }, 500);
        };
    }
    関数 sayHi() {
        console.log('手ぶれ補正成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 手ぶれ防止

Vue で使用しますか?

まず、私が以前陥った落とし穴についてお話しします。

次のコードはシーンの簡略版です

関数デバウンス(fn) {
        let timeout = null; // タイマーの戻り値を格納するマーカーを作成する return function () {
            clearTimeout(timeout); // ユーザーが入力するたびに、以前のsetTimeoutをクリアします。timeout = setTimeout(() => {
                // 次に、新しい setTimeout を作成します。これにより、入力文字の後の間隔内にさらに入力があった場合、fn 関数は実行されません。fn.apply(this, arguments);
            }, 500);
        };
   }

間違った使い方

<テンプレート>
    <div class="検索ビュー">
        <div class="header">
            <検索 
                クラス="検索ボックス" 
                v-model='検索値' 
                @input = '検索結果を取得' 
                placeholder='欲しいものを探す' />
            <span @click="goBack" class="cancel">キャンセル</span>
        </div>
        <div class="serach-view-content" />
    </div>

</テンプレート>

<スクリプト>
'./components/Search' から Search をインポートします。
'./config' から debounce をインポートします。

エクスポートデフォルト{
    名前: 'SearchView',
    コンポーネント:
        検索
    },
    データ() {
        戻る {
            検索値: ''
        };
    },
    メソッド: {
        検索結果を取得する() {
            デバウンス(関数() {
                console.log(this.searchValue);
            })();
        }
    }
};
</スクリプト>

なぜ間違っているのでしょうか?

ソースコードレベルの分析

Vue テンプレートのコンパイル解析イベント

エクスポート const onRE = /^@|^v-on:/
エクスポート const dirRE = /^v-|^@|^:/

関数 processAttrs(el) {
  定数リスト = el.attrsList
  let i、l、名前、値、修飾子
  (i = 0, l = list.length; i < l; i++) の場合 {
    名前 = リスト[i].名前
    値 = リスト[i].値
    if (dirRE.test(名前)) {
      // 修飾子の解析 modifiers = parseModifiers(name)
      if (修飾子) {
        名前 = 名前.replace(modifierRE, '')
      }
      if (onRE.test(name)) { // v-on
        名前 = 名前.replace(onRE, '')
        addHandler(el、名前、値、修飾子、false、warn)
      }
    }
  }
}

概要: インスタンス初期化フェーズ中に呼び出される初期化イベント関数 initEvents は、実際には、テンプレートで v-on または @ を使用して親コンポーネントによって登録されたリスナー子コンポーネントでトリガーされるイベントを初期化します。

Vueのイベントメカニズム

Vue.prototype.$on = 関数(イベント、fn) {
    定数 vm = this;
    if (Array.isArray(イベント)) {
        (i = 0 とします; i < イベントの長さ; i++) {
            this.$on(イベント[i], fn);
        }
    } それ以外 {
        // この _events 属性は、現在のインスタンスのイベント センターとして使用されます。このインスタンスにバインドされたすべてのイベントは、イベント センターの _events 属性に保存されます。
        (vm._events[イベント] || (vm._events[イベント] = [])).push(fn);
    }
    vm を返します。
};

Vue.prototype.$emit = 関数(イベント) {
    定数 vm = this;
    cbs = vm._events[イベント]とします。
    もし(CBS){
        cbs = cbs.length > 1 ? toArray(cbs): cbs;
        args = toArray(引数, 1);
        (i = 0 とします; i < cbs.length; i++) {
            試す {
                cbs[i].apply(vm, args);
            } キャッチ (e) {
                handleError(e, vm, `"${event}" のイベント ハンドラー`);
            }
        }
    }
    vm を返します。
};

initMethodsメソッドはvueのinitStateで呼び出されます

initMethodsでは、メソッドメソッドをこれに掛けます

for (const キー in メソッド) {
        process.env.NODE_ENV !== 'production' の場合 {
            if (メソッド[キー] == null) {
                警告(
                    `メソッド "${key}" にはコンポーネント定義内の未定義の値があります。` +
                        「関数を正しく参照しましたか?」
                    仮想
                );
            }
            // 名前がprops内のプロパティ名と同じ場合は例外がスローされます if (props && hasOwn(props, key)) {
                warn(`メソッド "${key}" はすでにプロパティとして定義されています。`, vm);
            }
            /*
            インスタンス vm に methods 内のメソッド名が既に存在し、メソッド名が _ または $ で始まる場合、例外がスローされます。
            メソッド名が標準化されていないことをユーザーに通知する*/
            if (キーがVM内にあり、isReserved(キー)) {
                警告(
                    `メソッド "${key}" は既存の Vue インスタンス メソッドと競合します。` +
                        「_ または $ で始まるコンポーネント メソッドの定義は避けてください。」
                );
            }
            // メソッドをインスタンス vm にバインドして、this.xxx を通じてアクセスできるようにします // 同時に、vue で let m1 = this.xxx m1() とすると、this も vue を指します
            vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
        }

要点:

  • サブコンポーネント $emit('input event')
  • 親コンポーネントがイベントを受信する
getSearchResult.apply(this、agrs) を実行します。
<===> apply の呼び出しは次のように記述できます。this.getSearchResult(args)

// そして、この実行は debounce(function() { になります。
      console.log(this.searchValue);
})();

// ここで debounce は関数を返すので、(function (fn) {
      clearTimeout(timeout); // ユーザーが入力するたびに、以前のsetTimeoutをクリアします。timeout = setTimeout(() => {
          // 次に、新しい setTimeout を作成します。これにより、入力文字の後の間隔内にさらに入力があった場合、fn 関数は実行されません。fn.apply(this, arguments);
      }, 500);
})()
// この時点で、実際には匿名関数の自己実行になります // 入力がトリガーされるたびに、新しい匿名関数が返されて新しい関数実行スタックが生成されるため、手ぶれ防止機能は失敗します〜

では、どう呼べばいいのでしょうか

<テンプレート>
    <div class="検索ビュー">
        <div class="header">
            <検索
                クラス="検索ボックス"
                v-model='検索値'
                @input = 'getSearchResult()'
                placeholder='欲しいものを探す'
            />
            <span
                @click="戻る"
                class="cancel">キャンセル</span>
        </div>
        <div class="serach-view-content">
            
        </div>
    </div>

</テンプレート>

<スクリプト>
'lodash.debounce' から debounce をインポートします。
エクスポートデフォルト{
    名前: 'SearchView',
    コンポーネント:
        検索、
    },
    データ() {
        戻る {
            検索値: ''、
        };
    },
    メソッド: {
        getSearchResult:デバウンス(関数() {
            console.log(this.searchValue);
        }, 500),
    },

};
</スクリプト>

実行プロセスを分析する

getSearchResult().apply(this, args)
<===> パラメータの動作を無視し、実行スタックのみに焦点を当てる let func = function () {
    clearTimeout(timeout); // ユーザーが入力するたびに、以前のsetTimeoutをクリアします。timeout = setTimeout(() => {
        // 次に、新しい setTimeout を作成します。これにより、入力文字の後の間隔内にさらに入力があった場合、fn 関数は実行されません。fn.apply(this, arguments);
    }, 500);
};

this.func(引数)

<===>

入力をトリガーするサブコンポーネントの動作は常に同じ関数本体を返します。アンチシェイクは成功します。

記事の冒頭で紹介したaddEventListenerと同様

要約する

これで、Vue でスロットリング関数を使用する際の落とし穴に関するこの記事は終わりです。Vue でスロットリング関数を使用する際の落とし穴に関する関連コンテンツの詳細については、123WORDPRESS.COM で以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • VUE の手ぶれ補正とスロットリングの最適なソリューションに関する簡単な説明 (機能コンポーネント)
  • Vueカスタムディレクティブを使用してスロットリング関数をカプセル化する方法の例
  • Vueは入力ボックスのファジークエリのサンプルコードを実装します(スロットリング機能の適用シナリオ)
  • Vue における機能アンチシェイクスロットリングの理解と応用
  • Vue コンポーネントのスロットリング機能が失敗する原因と解決策

<<:  Centos 7 sshd の変更 | ルートログインの禁止と sshd ポートスクリプトの定義

>>:  MySQL データのバックアップと復元のサンプル コード

推薦する

Linux の一般的なコマンドとショートカット キーの紹介

目次1 システムの紹介2 システムショートカット3 一般的なシステムコマンド1 システムの紹介 1....

Axios の二次カプセル化の例 プロジェクトのデモ

1. なぜパッケージングを行うのですか?全体的なコード呼び出し、リクエストの公開処理、パーソナライズ...

HTML でのメタタグと使用法の詳細な説明

これ以上無駄話をして時間を無駄にしないので、今日の話題を始めましょう。 HTML のメタタグ1. メ...

HBuilderX で Tomcat 外部サーバーを設定して、JSP インターフェイスを表示および編集する方法の詳細な説明

1. 最初の方法は、ローカルのTomcatを起動してJSPを表示することです。 tomcatのweb...

MySQL 実験: explain を使用してインデックスの傾向を分析する

概要インデックス作成は、MySQL で習得しなければならないスキルであり、MySQL クエリの効率を...

ウェブデザインにおける円形要素の使用例 25 選

本日の投稿では、Web デザインで使用される円形要素の優れた例をいくつか挙げ、美しい丸いボタン、メニ...

ローカルサーバーを構築するためのwebpack-dev-serverの実装

目次序文webpack-deb サーバーwebpack-dev-server 起動エラー解決策1解決...

一般的な XHTML タグの紹介

<br />しばらくの間、多くの人が XHTML の使い方を知らないことに気付きました。...

セマフォによるTomcatの異常終了の解決方法

最近はビッグデータで遊んでいます。友人が私のところに来て、オンラインの Tomcat が不可解に終了...

Angular Cookie の読み取りおよび書き込み操作コード

Angular Cookie の読み取りおよび書き込み操作のコードは次のようになります。 var a...

VueはEChartsを使用して折れ線グラフと円グラフを実装します

バックエンド管理プロジェクトを開発する場合、バックエンドのユーザーデータをカウントし、折れ線グラフや...

Windows Server 2008 64ビット MySQL5.6 インストール不要版 設定方法図

1 公式ウェブサイトから MySQL 5.6 バージョンの圧縮パッケージmysql-5.6.36-w...

MySQL における Datetime と Timestamp の使用の概要

目次1. MySQL で現在の時刻を表現するにはどうすればよいでしょうか? 2. TIMESTAMP...

PostgreSQL マテリアライズドビュープロセス分析

この記事は主にPostgreSQLマテリアライズドビューのプロセス分析について紹介します。サンプルコ...

HTMLとは何ですか?

HTML 開発の歴史: HTML は英語で Hypertext Marked Language の...