バックエンドから返される 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はヒントボックス、バブルボックス、三角形を作成します

場合によっては、ページにプロンプ​​ト ボックスやバブル ボックスが必要になることがあります。CSS...

MySQL の重要なログファイルの包括的なインベントリ

目次導入ログ分類パラメータファイルエラーログファイル完全なログファイルスロークエリログバイナリログフ...

HTML の著作権記号のフォント選択問題 (著作権記号をより美しくする方法)

1. 問題を発見する&copy; は HTML の著作権記号ですが、間違ったフォントを選択す...

Linux システムで複数のバージョンの PHP を共存させるソリューション (超シンプル)

PHP7が出たので、最新バージョンのファンとしては、早速アップグレードして体験してみました。しかし...

MySQL データベース トランザクション例のチュートリアル

目次1. トランザクションとは何ですか? 2. トランザクションに関連するステートメントは、挿入、削...

ReactプロジェクトにSCSSを導入する方法

まず依存関係をダウンロードします yarn sass-loader ノード sass を追加します次...

MySQL の簡単な分析 - MVCC

バージョンチェーンInnoDB エンジン テーブルでは、クラスター化インデックス レコードに 2 つ...

要素の読み込み効果を実現するための純粋なHTML+CSS

これは Element UI の読み込みコンポーネントのエフェクトです。かっこいいですね。実装してみ...

Vueはechartsを使用して組織図を描画します

昨日、円形のプログレスバー (Vue 円形プログレスバーを参照してください) についてブログを書きま...

方言変換のためのApache Calciteコード

意味Calcite は、Sql を SqlNode に解析し、次に SqlNode を特定のデータベ...

Linux インストール Redis 実装プロセスとエラー解決

今日、redis をインストールしたところ、今までになかったいくつかのエラーが発生しました。ここで記...

MySQL における ${param} と #{param} の違い

${param}によって渡されるパラメータは、テーブル名やフィールド名を渡すなど、SQL文の一部と...

HTMLのタグについての簡単な説明

0. タグとは何ですか? XML/HTML コードコンテンツをクリップボードにコピー<入力 t...

keepalived+nginx の高可用性を実装する方法の例

1. keepalived の紹介Keepalived は、もともと LVS クラスタ システム内の...

MySQLの実行原理、論理階層化、データベース処理エンジンの変更について詳しく説明します

長い間 MySQL を使ってきたので、SQL 文はすでに覚えていると思います。そこで、その実行原理を...