大量データをテーブル表示してもブラウザを固まらせない(Vue.js?)

テーブルに数千件データを表示しようとするとブラウザが音を上げる。

業務ツールの開発だとひたすらデータを便利に処理したい要望が多いので、CSVやテーブルを使って大量のデータを処理できるような仕様となることが多い気がします。ページネーション?データ眺めるんじゃなくて仕事で処理したいのですわ、一つのテーブルに数千件など入れて操作させてくれなどもありました。上手くインデックスやキーが貼られていてSQLや裏側は何とかなっても今度はブラウザに一斉にデータを描画しようとするとフリーズしてしまう。特にChromeが遅いと言っている人もいるが今はChromeの時代なのでChromeで遅いのはまずい状態です。

固まってしまっていたコード(before)

結構前のコードなので若干細部はうる覚えだが、こんな感じでLaravelからデータを取得して、Vue.jsの色々できる便利テーブルライブラリにrowsとしてデータを入れ込めば綺麗に表示されるという形で、queryParamsの中には表示したいデータ数をユーザーがリクエストできるような仕様にしていました。表示するデータが10-100件などは特に問題なかったのですが、1000件超えた辺りから、ブラウザが10秒近く固まるようになってしまいました。

freezeTable() {
            let self = this;
            axios
                .get( "/tablelist", {
                    params: {
                        queryParams: this.queryParams
                    }
                })
                .then(function(response) {
                    let tables = response.data.data;
                   self.rows = tables;
        }) 
        .catch(function(error) { 
            //例外処理
        },
}

JavaScriptのイベントループを理解する
setTimeout(...,0)などの使いドコロ
JavaScriptで大量のinput等のDOM操作がChromeだけ重いので解決する

setTimeoutを利用すたコード(after)

setTimeout関数を利用して、イベントループを進めて100個ずつのデータを順番にテーブルに入れて表示していくようにしました。これでブラウザは全部のデータの描画を待たずに100個ずつデータを表示してくれるようになりました。大量のデータをまとめて一括で挿入するサーバーサイドやSQLのバルクインサートに対して、描画が重すぎるので分けるためにこれは逐次レンダリングと言えるのでしょうか。

smoothTable() {
     let self = this;
     axios
          .get( "/tablelist", {
                params: {
                   queryParams: this.queryParams
                }
          })
          .then(function(response) {
               let tables = response.data.data;
                              
               self.rows = [];
               while (true) {
                   const table_hundred = tables.splice(0, 100);
                      if (table_hundred.length <= 0) break; 
                        setTimeout(() => {
                             for (let len = table_hundred.length, i = 0; i < len; i++) { 
                               const th = table_hundred[i] 
                               self.rows.push(th); 
                            } 
                        }
                   ); 
             } 
       }) 
       .catch(function(error) { 
            //例外処理
        }
}

以下の記事はこれを書く上で非常に参考になりました、ひとまず要件を満たすコードを作成することができた。色々調べてもあまり情報がすぐには見つからなかったので、皆様はまず仕様をこのような形にさせない賢さを持っているもしくは私が見つけることができなかった別の手段を見つけたのか果たして? Lazy Loadとか遅延処理とかもしっかり理解して扱えるようになりたいものですね。

How can I render elements in v-for loop with different times?
Vue.jsで大量の配列要素を滑らかに描画

おすすめの記事