バックエンドから返される 100,000 個のデータをフロントエンドでより適切に表示するにはどうすればよいですか?

バックエンドから返される 100,000 個のデータをフロントエンドでより適切に表示するにはどうすればよいですか?

今日はこれについてお話ししましょう。バックエンドが実際に 100,000 個のデータをフロントエンドに返す場合、フロントエンドでそれらをエレガントに表示するにはどうすればよいでしょうか?

予備作業

まず予備作業を行い、その後でテストします。

バックエンド構築

新しいserver.jsファイルを作成し、簡単なサービスを開始し、 10w個のデータをフロントエンドに返し、 nodemon server.jsを通じてサービスを開始します。

nodemonがインストールされていない場合は、まずnpm i nodemon -gでグローバルにインストールできます。

// サーバー.js
定数 http = require('http')
ポート = 8000; 
http.createServer(関数(req, res) {
  // Cors を有効にする
  res.writeHead(200, {
    //ドメイン間で許可されるドメイン名を設定します。すべてのドメイン名を許可するには * を設定することもできます。'Access-Control-Allow-Origin': '*',
    //クロスドメインで許可されたリクエストメソッド。* を設定してすべてのメソッドを許可することもできます "Access-Control-Allow-Methods": "DELETE、PUT、POST、GET、OPTIONS",
    // 許可されるヘッダーの種類 'Access-Control-Allow-Headers': 'Content-Type'
  })
  リスト = []
  数値を0にする
 
  // 100,000件のレコードのリストを生成する
  (i = 0; i < 1000000; i++ とします) {
    数値++
    リスト.push({
      ソース: 'https://p3-passport.byteacctimg.com/img/user-avatar/d71c38d1682c543b33f8d716b3b734ca~300x300.image',
      テキスト: `私はゲスト番号 ${num} の Lin Sanxin です`、
      tid: 番号
    })
  }
  res.end(JSON.stringify(リスト));
}).listen(ポート、関数() {
  console.log('サーバーはポート ' + ポートでリッスンしています);
})

フロントエンドページ

まず新しいindex.htmlを作成します

// インデックス.html
// スタイル <style>
    * {
      パディング: 0;
      マージン: 0;
    }
    #容器 {
      高さ:100vh;
      オーバーフロー:自動;
    }
    .sunshine {
      ディスプレイ: フレックス;
      パディング: 10px;
    }
    画像 {
      幅: 150ピクセル;
      高さ: 150px;
    }
  </スタイル> 
// html 部分 <body>
  <div id="コンテナ">
  </div>
  <script src="./index.js"></script>
</本文>

次に、新しいindex.jsファイルを作成し、これらの10wデータをリクエストするAJAX関数をカプセル化します。

// インデックス.js 
// リクエスト関数 const getList = () => {
    新しい Promise を返します ((resolve, reject) => {
        //ステップ 1: 非同期オブジェクトを作成する var ajax = new XMLHttpRequest();
        //ステップ 2: リクエスト URL パラメータを設定します。パラメータ 1 はリクエスト タイプ、パラメータ 2 はリクエスト URL です。ajax.open('get', 'http://127.0.0.1:8000'); を使用できます。
        //ステップ 3: リクエストを送信する ajax.send();
        //ステップ4: onreadystatechangeイベントを登録します。状態が変化すると、ajax.onreadystatechange = function () {
            ajax.readyState == 4 かつ ajax.status == 200 の場合 {
                //ステップ 5 ここまで到達できれば、データが完全に返され、要求されたページが存在することを意味します。resolve(JSON.parse(ajax.responseText))
            }
        }
    })
} 
// コンテナオブジェクトを取得します。const container = document.getElementById('container')

ダイレクトレンダリング

最も直接的な方法は直接レンダリングすることですが、一度に10wノードをレンダリングするのは非常に時間がかかるため、この方法は絶対にお勧めできません。時間の消費量を見てみましょう。約12秒かかり、非常に時間がかかります。

const レンダリングリスト = 非同期 () => {
    console.time('リスト時間')
    const リスト = getList() を待つ
    リスト.forEach(項目 => {
        定数div = document.createElement('div')
        div.className = 'sunshine'
        div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
        コンテナ.appendChild(div)
    })
    console.timeEnd('リスト時間')
}
レンダリングリスト()

setTimeout ページングレンダリング

この方法は、1ページあたりのページ数limitに応じて、 10w合計Math.ceil(total / limit)ページに分割し、 setTimeoutを使用して毎回1ページのデータをレンダリングします。これにより、ホームページデータのレンダリング時間が大幅に短縮されます。

const レンダリングリスト = 非同期 () => {
    console.time('リスト時間')
    const リスト = getList() を待つ
    console.log(リスト)
    定数合計 = リスト.長さ
    定数ページ = 0
    定数制限 = 200
    const totalPage = Math.ceil(合計 / 制限) 
    const render = (ページ) => {
        if (page >= totalPage) 戻り値
        タイムアウトを設定する(() => {
            (i = ページ * 制限; i < ページ * 制限 + 制限; i++) {
                const 項目 = リスト[i]
                定数div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                コンテナ.appendChild(div)
            }
            レンダリング(ページ + 1)
        }, 0)
    }
    レンダリング(ページ)
    console.timeEnd('リスト時間')
}

リクエストアニメーションフレーム

setTimeoutの代わりにrequestAnimationFrameを使用すると、重排の回数が減り、パフォーマンスが大幅に向上します。レンダリングではrequestAnimationFrameより頻繁に使用することをお勧めします。

const レンダリングリスト = 非同期 () => {
    console.time('リスト時間')
    const リスト = getList() を待つ
    console.log(リスト)
    定数合計 = リスト.長さ
    定数ページ = 0
    定数制限 = 200
    const totalPage = Math.ceil(合計 / 制限)
    const render = (ページ) => {
        if (page >= totalPage) 戻り値
        // setTimeout の代わりに requestAnimationFrame を使用する
        リクエストアニメーションフレーム(() => {
            (i = ページ * 制限; i < ページ * 制限 + 制限; i++) {
                const 項目 = リスト[i]
                定数div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                コンテナ.appendChild(div)
            }
            レンダリング(ページ + 1)
        }, 0)
    }
    レンダリング(ページ)
    console.timeEnd('リスト時間')
}

ドキュメントフラグメント + requestAnimationFrame

ドキュメントの断片化の利点

1. 以前は、 divタグが作成されるたびにappendChildが呼び出されていました。しかし、ドキュメント フラグメントを使用すると、1 ページのdivタグを最初にドキュメント フラグメントに配置し、次にcontainerappendChild一度に呼び出すことができます。これにより、 appendChild呼び出しの回数が減り、パフォーマンスが大幅に向上します。

2. ページはドキュメントフラグメントで囲まれた要素のみをレンダリングし、ドキュメントフラグメント自体はレンダリングしません。

const レンダリングリスト = 非同期 () => {
    console.time('リスト時間')
    const リスト = getList() を待つ
    console.log(リスト)
    定数合計 = リスト.長さ
    定数ページ = 0
    定数制限 = 200
    const totalPage = Math.ceil(合計 / 制限) 
    const render = (ページ) => {
        if (page >= totalPage) 戻り値
        リクエストアニメーションフレーム(() => {
            // ドキュメントフラグメントを作成する constfragment = document.createDocumentFragment()
            (i = ページ * 制限; i < ページ * 制限 + 制限; i++) {
                const 項目 = リスト[i]
                定数div = document.createElement('div')
                div.className = 'sunshine'
                div.innerHTML = `<img src="${item.src}" /><span>${item.text}</span>`
                // まずドキュメントフラグメントを挿入します。fragment.appendChild(div)
            }
            // 1回限りのappendChild
            コンテナ.appendChild(フラグメント)
            レンダリング(ページ + 1)
        }, 0)
    }
    レンダリング(ページ)
    console.timeEnd('リスト時間')
}

遅延読み込み

より一般的な説明として、 vueフロントエンド プロジェクトを開始し、バックエンド サービスはまだ開いているとします。

実際、実装の原理は非常に簡単です。図で説明しましょう。リストの最後にblankのノードを置き、最初に最初のページのデータをレンダリングし、上にスクロールして、ビューにblank表示されるまで待機します。これは終了を意味します。次に、2 番目のページをロードします。

ビューにblankが表示されるかどうかを判断するには、 getBoundingClientRectメソッドを使用してtop属性を取得します。

<スクリプト設定 lang="ts">
'vue' から { onMounted, ref, computed } をインポートします。
定数getList = () => {
  //上記と同じコード}
const container = ref<HTMLElement>() // コンテナノード const blank = ref<HTMLElement>() // 空白ノード const list = ref<any>([]) // リスト const page = ref(1) // 現在のページ番号 const limit = 200 // 1 ページ表示 // 最大ページ数 const maxPage = computed(() => Math.ceil(list.value.length / limit))
// 実際に表示されるリスト const showList = computed(() => list.value.slice(0, page.value * limit))
const ハンドルスクロール = () => {
  // 現在のページ番号と最大ページ番号の比較 if (page.value > maxPage.value) return
  const clientHeight = コンテナ.value?.clientHeight
  定数 blankTop = blank.value?.getBoundingClientRect().top
  if (clientHeight === blankTop) {
    // ビューに空白が表示され、現在のページ番号が 1 増加します
    ページ.値++
  }
} 
onMounted(非同期() => {
  const res = getList() を待つ
  リスト.値 = res
})
</スクリプト> 
<テンプレート>
  <div class="コンテナ" @scroll="handleScroll" ref="コンテナ">
    <div class="sunshine" v-for="(item) in showList" :key="item.tid">
      <img :src="item.src" />
      <span>{{ 項目.テキスト }}</span>
    </div>
    <div ref="空白"></div>
  </div>
</テンプレート>

上記は、バックエンドから返された 10 万個のデータをフロントエンドでより適切に表示する方法についての詳細です。バックエンドから返された 10 万個のデータをフロントエンドで表示する方法の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript で一度に数万件のデータを一括表示する方法
  • 大量のデータに対する js フロントエンド表示および処理方法
  • Javaはフロントエンドでバックグラウンドデータの表示を実現します
  • フロントエンドとバックエンドのデータインタラクションを実装する方法の概要

<<:  HTML のテキストエリアの改行問題の概要

>>:  有名なブログの再設計例 28 件

推薦する

CSS で div 凹角スタイルを実装するサンプル コード

通常の開発では、凸型の丸い角、つまり border-radius 属性を使用するのが一般的です。凹角...

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

この記事では、MySQL 5.7.17 winx64解凍版のインストールと設定方法を紹介します。具体...

MySQL ディープページング問題の解決の実践記録

目次序文ディープページングを制限すると遅くなるのはなぜですか?サブクエリによる最適化B+ツリー構造の...

MySQL 操作: JSON データ型の操作

前回の記事では、MySQL データ保存手順パラメータの詳細な例を紹介しました。今日は、JSON デー...

Nodejsはgitee実装コードに自動的に同期するドキュメント同期ツールを作成します

本来の意図このツールを作った理由は、コンピューターを使用しているときにいつでも毎日の仕事や生活を記録...

SQL における distinct と row_number() over() の違いと使い方

1 はじめにデータベース内のデータを操作するための SQL 文を記述するときに、いくつかの不快な問題...

Vue フロントエンド開発における階層的にネストされたコンポーネント間の通信の詳細な説明

目次序文例まとめ序文Vue の親子コンポーネントは、props を通じて親コンポーネントの値を子コン...

MySQL をデプロイするときに発生する「テーブル mysql.plugin が存在しません」という問題の解決方法

今日、MySQL の無料インストール版をデプロイしたところ、テーブル 'mysql.plug...

MySQL (8 および 5.7) の Docker インストール

この記事では、Dockerを使用してMySQLデータベースとリモートアクセス構成をデプロイする方法を...

Vue で Openlayer を使用して読み込みアニメーション効果を実現する

注意: スコープアニメーションは使用できません。 ! ! ! GIF経由 <テンプレート>...

テーブル内の要素のドラッグと並べ替えの問題について簡単に説明します

最近、要素テーブルを使用すると、並べ替えの問題によく遭遇します。単純な並べ替えであれば、要素の公式が...

MySQL 5.7.13 ソースコードのコンパイル、インストール、および構成方法のグラフィックチュートリアル

インストール環境: CentOS7 64ビットMINI版公式ソースコードのコンパイルおよびインストー...

Mysqlデータベースの文字化けに対処する方法

MySQL では、データベースの文字化けは一般的に文字セットを設定することで修正できますが、文字化け...

CSSに基づいてマウス入力の方向を決定する

以前、フロントエンド技術グループに所属していたとき、グループのメンバーが面接中に問題に遭遇したと言っ...

Ubuntu 20.04 では、隠し録音ノイズ低減機能が有効になります (推奨)

最近、 Ubuntu 20.04でkazamを使用して録音しているときに、問題が見つかりました。シス...