Vue.js でリアクティブを捨てて高速にレンダリングする

Vue.js + vue2-leaflet で v-for を利用している箇所で明らかに遅くなる事象にぶつかってしまいました.

20 個程度の配列だとなめらかに動くのに何千個の配列を扱うとかなり重くなってメモリをモリモリ食って Chrome を落としてしまうほどになってしまうほどでした.

Object.freeze()

リアクティブから解き放つには Object.freeze() を利用すると良いようです.リアクティブを諦めることで高速化を望めるようです.

1
2
3
4
5
6
7
8
9
data: function () {
return {
data: {"id": 123, "name": "hoge", ...}
}
}

mounted(): {
this.data = Object.freeze(this.data)
}

早速試してみましたが,どうやら恩恵が受けられているとは思えず速度が改善することはありませんでした.

深くまで Object.freeze() が効かない

例えば以下のように,

1
2
3
4
5
6
7
8
deta = {"id": 123,
"name": "hoge",
"like": { // ここまで効いてない
"fruit": "strawberry",
"pasta": "carbonara",
...
}
}

子のプロパティを持っていた場合,子は freeze されていないようです.

再帰的に実行することで深くまで Object.freeze() してあげると良さそうです.(あんまり深いとパフォーマンスが心配になりますが)

1
2
3
4
5
6
7
8
methods: {
deepFreeze(obj) {
Object.keys(obj).forEach(prop => {
if (typeof obj[prop] === 'object' && !Object.isFrozen(obj[prop])) deepFreeze(obj[prop]);
});
return Object.freeze(obj);
}
};

これで無事解決しました.

Devtools を導入していない環境で確認してみる

なぜか Vue Devtools 拡張を導入していると遅くなる事象が発生するようです.

悩む前に一度シークレットモードなどで試してみたほうが良さそうです.

参考

タイトル通りなのでとりあえず結果を見てもらいましょう。

See the Pen
EMNpVM by isuke (@isuke)
on CodePen.

実行結果 “

正確な測定ではないですが明らかな速…

The official 30-seconds blog. Contribute to 30-seconds/30-seconds-blog development by creating an account on GitHub.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×