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 データのバックアップと復元のサンプル コード

推薦する

登録フォームのデザインルール

随分前に「Patterns for Sign Up & Ramp Up」を読み終えました。今...

DIV共通属性コレクション

1. 物件リストコードをコピーコードは次のとおりです。色: #999999 テキスト色フォントファミ...

Vite と Vue CLI の長所と短所

Vue エコシステムには Vite と呼ばれる新しいビルド ツールがあり、Vue CLI よりも 1...

Docker ベースの Tomcat クラスタと Nginx ロード バランシングの展開の概要

目次前面に書かれた1. Ngixnイメージの作成2. Java Web (Tomcat) アプリケー...

HTML における iFrame タグの 2 つの使用法

最近、私は「ぶどうコレクション」というプロジェクトに取り組んでいます。簡単に言うと、Budou ペー...

Docker swarm の簡単なチュートリアル

3つの仮想マシン132、133、134を群がらせる1. クラスターを初期化し、自分自身をクラスターに...

LinuxでRPMを使用してmysql5.7.17をインストールする

LinuxでのMySQL5.7 rpmのインストール方法を参考までに記録します。具体的な内容は以下の...

WIN10 に複数のデータベースがインストールされている場合にコンピュータの速度低下を防ぐ方法

必要なときにサービスを有効にし、必要がないときは無効にします。データベース サービスを管理する方法:...

MySQL のデータベース パフォーマンスに影響を与える要因の説明

データベースのパフォーマンスに関する話面接では、「データベースにどのくらい精通していますか?」など、...

MySQLを水平から垂直に、垂直から水平に変換する方法

データの初期化 `test_01` が存在する場合はテーブルを削除します。 テーブル「test_01...

Mysql5.7.14 インストールと設定方法操作グラフィックチュートリアル(パスワード問題解決)

この記事は主に、以前のインストール方法を使用して MySQL 5.7.14 をインストールするときに...

VUEをベースにしたシンプルな学生情報管理システムの実装

目次1. 主な機能2. 実装のアイデア3. コードの実装4. エフェクト表示V. 結論1. 主な機能...

JConsoler を使って Tomcat の JVM メモリを監視する方法を説明します

目次1. Tomcatを監視する方法2. Java独自の監視コマンド3. Tomcatのトラブルシュ...

DockerHubイメージリポジトリの使い方の詳しい説明

これまで使用していたイメージはすべて DockerHub パブリック リポジトリから取得していました...

JavaScriptはイベントリスナーをイベント委任にバッチで追加します。詳細なプロセス

1. イベント委任とは何ですか?イベント委譲: イベントバブリングの特性を利用して、子要素に登録すべ...