Vue 組み込みコンポーネントのキープアライブでの LRU アルゴリズムの使用

Vue 組み込みコンポーネントのキープアライブでの LRU アルゴリズムの使用

Vue の keep-alive 組み込みコンポーネントの使用でもこのアルゴリズムが使用されます。ソース コードは次のとおりです。

エクスポートデフォルト{
  名前: "キープアライブ"、
  // コンポーネントインスタンスが親子関係を確立するときに無視される抽象コンポーネントプロパティ。これは initLifecycle プロセス中に発生します。abstract: true, 
  小道具: {
    // キャッシュコンポーネントには、patternTypes、 
    // キャッシュから除外するコンポーネント: patternTypes、
    // キャッシュサイズの最大値を指定します: [文字列、数値] 
  },
  作成された() {
    // キャッシュを保存するために使用するキャッシュ オブジェクトを初期化します。this.cache = Object.create(null);
    // VNode キー値を格納するために使用するキー配列を初期化します。this.keys = []; 
  },
  破壊された() {
    for (const キー in this.cache) {
      // すべてのキャッシュを削除します pruneCacheEntry(this.cache, key, this.keys);
    }
  },
  マウント() {
    // キャッシュ(含める)/除外コンポーネントの変更をリッスンする // 変更が発生したらキャッシュを再調整する
    // pruneCache: キャッシュを走査し、キャッシュされたノード名が渡されたルールと一致しない場合は、キャッシュからノードを削除します this.$watch("include", val => {
      pruneCache(this、name => matches(val、name));
    });
    this.$watch("exclude", val => {
      pruneCache(this、name => !matches(val、name));
    });
  },
  与える() {
    // 最初の子要素のvnodeを取得します
    const スロット = this.$slots.default;
    const vnode: VNode = getFirstComponentChild(スロット);
    定数コンポーネントオプション: ?VNodeComponentOptions =
      vnode && vnode.componentOptions;
    if (コンポーネントオプション) {
      // 名前が include または exclude にない場合は、vnode を直接返し、それ以外の場合は次のステップに進みます // パターンをチェックします
      定数名: ?string = getComponentName(componentOptions);
      const { include, exclude } = this;
      もし (
        // 含まれません
        (include && (!name || !matches(include, name))) ||
        // 除外
        (exclude && name && matches(exclude, name))
      ){
        vnode を返します。
      }
      
      const { キャッシュ、キー } = this;
      // キーを取得し、最初にコンポーネントの名前フィールドを取得します。それ以外の場合はコンポーネントのタグになります。
      定数キー: ?文字列 =
        vnode.key == null
          ? // 同じコンストラクタが異なるローカルコンポーネントとして登録される可能性があります
            // cid だけでは不十分です (#3269)
            コンポーネントオプション.Ctor.cid +
            (componentOptions.tag ? `::${componentOptions.tag}` : "")
          : vnode.key;
        
      // --------------------------------------------------
      // 以下はLRUアルゴリズムです。
      // キャッシュ内にある場合は調整します。
      // そうでない場合は入れます(長さが最大値を超える場合は、最近アクセスされていないものを削除します)
      // --------------------------------------------------
      // キャッシュにヒットした場合は、キャッシュからvnodeのコンポーネントインスタンスを取得し、キーの順序をキー配列の末尾に調整します。if (cache[key]) {
        vnode.componentInstance = キャッシュ[キー].componentInstance;
        // 現在のキーを最新のものにする
        削除(キー、キー);
        keys.push(キー);
      }
      // キャッシュにヒットしない場合は、vnode をキャッシュに格納します。else {
        キャッシュ[キー] = vnode;
        keys.push(キー);
        // 最も古いエントリを削除する
        // maxが設定されていて、キャッシュの長さがthis.maxを超える場合は、キャッシュから最初のものを削除します。if (this.max && keys.length > parseInt(this.max)) {
          キャッシュエントリを削除します(キャッシュ、キー[0]、キー、this._vnode);
        }
      }
      
      // キープアライブフラグ vnode.data.keepAlive = true;
    }
    vnode || (slot && slot[0]) を返します。
  }
};

// キーキャッシュを削除する関数pruneCacheEntry(
  キャッシュ: VNodeCache、
  キー: 文字列、
  キー: 配列<文字列>,
  現在の?: VNode
){
  const キャッシュ = キャッシュ[キー]
  if (cached && (!current || cached.tag !== current.tag)) {
    キャッシュされたコンポーネントインスタンス.$destroy()
  }
  キャッシュ[キー] = null
  削除(キー、キー)
}

// メソッドを削除 (shared/util.js)
/**
 * 配列から項目を削除します。
 */
エクスポート関数remove (arr: Array<any>, item: any): Array<any> | void {
  (arr.length)の場合{
    定数インデックス = arr.indexOf(item)
    (インデックス>-1)の場合{
      arr.splice(インデックス, 1) を返す
    }
  }
}

独自のLRUアルゴリズムの実装

lru アルゴリズムのコア API (put get) と最大コンテナ値のサイズは、基本的にキュー put の実装アイデアに似ています。1. 存在する場合は、まずそれを削除してからキューの先頭に追加します。2. 存在しない場合は、容量がいっぱいかどうかに関係なく、キューの最後の末尾を削除してからキューの先頭を追加します。get の実装アイデア: 1. 存在する場合は返し、キューの先頭に挿入します。2. 存在しない場合は、-1 を返します。時間計算量 O(1)

クラスLRU {
  コンストラクタ(サイズ) {
    this.cache = 新しいマップ()
    this.size = サイズ
  }
  (キー、値) を置く {
    //存在する場合(this.cache.has(key)) {
      //削除 this.cache.delete(key)
    } それ以外 {
      // 存在しない、容量がいっぱいです if (this.size === this.cache.size) {
        //最後のものを削除します this.cache.delete(this.cache.keys().next().value) //キューの末尾の要素を取得します}
    }
    //キューの先頭に挿入 this.cache.set(key, val)
  }
  取得 (キー) {
    val = this.cache.get(キー) とします。
    もし(!val) {
      -1を返す
    }
    //アクセス後、キューの先頭に配置する必要があります this.put(key, val)
    戻り値
  }
}

別の

//ノードクラスを定義する class Node {
    コンストラクタ(前、次、値、キー){
        this.pre = pre;
        this.next = 次へ;
        this.value = 値;
        this.key = キー;
    }
}

//双方向リンクリストクラスを定義する DoubleList {
    コンストラクタ(head, tail){
        this.head = ヘッド;
        this.tail = テール;
    }
}


クラスLRUCache {
    //コンストラクタ、キャッシュ容量を渡すconstructor(max){
        this.max = 最大値;
        this.map = 新しい Map();
        ノードを新しいノード(null, null, null, null);
        this.doubleList = 新しい DoubleList(node, node);
    }
    
    /**
     * キャッシュ値を取得します * 存在しない場合は -1 を返します。存在する場合は、対応する値を返してこのノードを末尾に移動します * @param {*} key key value */
    get(キー){
        ノード = this.map.get(キー)
        if(!ノード){
            -1 を返します。
        }それ以外{
            this.moveNode2Tail(キー、ノード);
            ノード値を返します。
        }
    }

    /**
     * キャッシュを挿入 * 1. 対応するキー値が存在しない場合は末尾に追加します * 2. 対応するキー値が存在する場合は、このキー値に対応する値を更新して末尾に記述します * 3. 容量を超えた場合は、ヘッダーデータを削除します * @param {*} key キー値 * @param {*} value 値
     */
    put(キー, 値) {
        ノード = this.map.get(キー);
        if(ノード){
            if(!node.next){
                ノードの値 = 値;
                戻る;
            }
            node.pre.next = node.next;
            ノードを次のノードにリンクします。
        }
        newNode = new Node(null, null, 値, キー);
        newNode.pre = this.doubleList.tail;
        this.doubleList.tail.next = 新しいノード;
        this.doubleList.tail = newNode;
        this.map.set(キー、newNode);
        このマップのサイズがこれより大きい場合、
            this.map.delete(this.doubleList.head.next.key);
            this.doubleList.head.next = this.doubleList.head.next.next;
            this.doubleList.head.next.pre = this.doubleList.head;          
        }
    }
    
    //ノードを末尾に移動する moveNode2Tail(key,node){   
        if(!node.next){
            戻る;
        }
        //ノードを削除します。node.pre.next = node.next;
        ノードを次のノードにリンクします。
        this.map.delete(キー)
        //新しい末尾ノードを追加します。let newNode = new Node(null, null, node.value, key);
        newNode.pre = this.doubleList.tail;
        this.doubleList.tail.next = 新しいノード;
        this.doubleList.tail = newNode;
        this.map.set(キー、newNode);
    }
}

上記は、Vue の組み込みコンポーネントのキープアライブにおける LRU アルゴリズムの使用に関する詳細な内容です。Vue LRU アルゴリズムの詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Vue3の組み込みコンポーネントであるTeleportの使い方を詳しく説明します
  • Vue組み込みコンポーネントのキープアライブの使用例
  • vue.js組み込みコンポーネントのキープアライブコンポーネントの使用
  • Vue の新しい組み込みコンポーネントの使用方法の詳細な説明

<<:  MySQL 8.0.13 解凍版のインストールと設定方法のグラフィックチュートリアル

>>:  CentOS 8が利用可能になりました

推薦する

ノードでシェルスクリプトを使用する方法

背景開発中、特定の状況でビジネス ロジックをバッチ処理するためのスクリプトが必要になる場合があります...

nodejs + koa + typescript の統合と自動再起動に関する問題

目次バージョンノートプロジェクトを作成する依存関係をインストールするコンテンツの記入src/serv...

XHTML チュートリアル: Transitional と Strict の違い

実際、XHTML 1.0 は、Transitional DOCTYPE と Strict DOCTY...

jQuery ツリービュー ツリー構造アプリケーション

この記事では、jQueryツリービューツリー構造のアプリケーションコードを例として紹介します。具体的...

Nginxを使用してストリーミングメディアサーバーを構築し、ライブブロードキャスト機能を実現する

前面に書かれた近年、ライブストリーミング業界は非常に人気が高まっています。伝統的な業界でのライブスト...

Vueは、サイドナビゲーションバーをタブページに関連付けるサンプルコードを実装します。

目次テクノロジースタック効果分析するテクノロジースタックサイドバー用Antdtabは要素を使用します...

MySQL を使用した分散ロックの実装

導入分散システムでは、分散ロックは最も基本的なツール クラスです。たとえば、支払い機能を備えた 2 ...

Dockerでプロジェクトを実行する方法

1. プロジェクトwarが保存されているディレクトリを入力しますDockerfileを編集する vi...

HTML 名、ID、クラス (フォーマット/アプリケーション シナリオ/機能) などの違いの紹介。

ページには多くのコントロール (要素またはタグ) があります。これらのタグをより便利に操作するには、...

JS WebSocketを使用して簡単なチャットを実装する方法

目次ショートポーリングロングポーリングウェブソケットコミュニケーションの原則シンプルな1対1チャット...

CSS を使用して要素のスクロールバーを非表示にするサンプルコード

どの要素でもスクロールできるようにしながら、スクロールバーを非表示にするにはどうすればよいでしょうか...

Vue プロジェクトでよく使用されるツール機能の概要

目次序文1. カスタムフォーカスコマンド1. 方法1 2. 方法2 3. 方法3 2. 入力ボックス...

document.getElementBy系メソッドがオブジェクトを取得できない問題を解決する

getElementByIdはオブジェクトを取得できませんブラウザがドキュメントを解析するときにはシ...

JavaScript の navigator.userAgent がブラウザ情報を取得するケースの説明

ブラウザはおそらく私たちにとって最も馴染みのあるツールです。 Firefox、Opera、Safar...

XAML でボタンを円として再描画する方法

XAML レイアウトを使用する場合、インターフェイスを Metro 風にするために、一部のボタンでは...