バックエンドから返される 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 件

推薦する

JavaScript で charAt() を使用して、最も頻繁に出現する文字とその出現回数をカウントする方法を教えます。

前回は、JavaScript の charAt() メソッドの使い方を紹介しました。今日は、最も多く...

HTMLの水平線注釈とコードコメントの使い方をマスターするだけです

水平線<hr /> タグを使用して、現在の位置に水平の分割線を描画します。例: XML/...

Nginx の書き換え正規マッチング書き換え方法の例

Nginx の書き換え機能は、リダイレクトと同様に、URL アドレスを一時的または永続的に新しい場所...

Elementはスクリプトを使用して新しいコンポーネントを自動的に構築します

目次背景element-ui の自動構築はどのように機能しますか?メイクファイル新しい.jsファイル...

MySQL5.6.31 winx64.zip インストールと設定のチュートリアル

#1. ダウンロード # #2. ローカルに解凍し、必要な構成のmy*.iniを変更します。 #3....

忘れられたボタンタグ

注:この記事は他の人によって翻訳されていますが、考えるべき点が多く、理解しにくい点もあると感じていま...

MySQL の列から行への変換のヒント (共有)

序文:多くのビジネス テーブルでは、歴史的またはパフォーマンス上の理由により、最初のパラダイムに違反...

MySQLデータベースのロック機構の分析

同時アクセスの場合、非反復読み取りやその他の読み取り現象が発生する可能性があります。高い同時実行性に...

Vue3+Element+Tsは、フォームの基本的な検索リセットやその他の機能を実装します

Vue2 の記述スタイルから Vue3 の形式に切り替えると、記述スタイルとコード構造にいくつかの変...

シンプルなウェブデザインコンセプトのカラーマッチング

(I)ウェブページのカラーマッチングの基本概念(1)白黒の言葉は永遠のテーマです。誰もそれを悪く言う...

mysql エラー 1045 (28000) - ユーザーへのアクセスが拒否される問題を解決する方法

問題の説明 (以下の説明は Windows 環境に限定されます): D:\develop\ide\m...

CSS 要素の非表示の原則と display:none および visibility:hidden

1. CSS 要素の非表示<br />CSS では、要素を非表示にする (つまり、画面の...

フォーム送信の更新ページはソースコード設計にジャンプしません

1. ソースコードの設計コードをコピーコードは次のとおりです。 <!DOCTYPE html ...

Mac に mysql5.7 をインストールするための完全な手順 (画像とテキスト付き)

最近、Mac システムを使用して、ローカル Web サーバー環境を構築する準備をしていました。 Ma...

アイデア展開Tomcatサービス実装プロセス図

まずプロジェクトの成果物を構成するスタートアップ項目の設定 Tomcatサービスを作成する開始したい...