フロントエンドのパフォーマンス改善施策 (Vue.jsを使用)
1. WebWorkerで重い処理のブロッキングを解消
パフォーマンス改善において、CPUを大量に消費するような処理は、WebWorkerを使用してメインスレッドのブロッキングを避けることができます。
WebWorkerを利用することで、重い処理を別のスレッドで実行し、UIのレスポンス性を維持します。
これは、複雑な計算やデータ処理が必要なアプリケーションで効果的です。
改善前:
<script setup>
import { ref, onMounted } from 'vue';
const result = ref(0);
function heavyFunction(num1, num2) {
let result = 0;
for (let i = 0; i < num1; i++) {
for (let j = 0; j < num2; j++) {
result = i * j;
}
}
return result;
}
onMounted(() => {
result.value = heavyFunction(30000, 30000);
});
</script>
<template>
<div>計算結果: {{ result }}</div>
</template>
改善後:
<script setup>
import { ref, onMounted } from 'vue';
const result = ref(0);
onMounted(() => {
const worker = new Worker(new URL('./my-worker.js', import.meta.url));
worker.postMessage({ a: 30000, b: 30000 });
worker.onmessage = (e) => {
result.value = e.data;
};
});
</script>
<template>
<div>計算結果: {{ result }}</div>
</template>
// my-worker.js
function heavyFunction(num1, num2) {
let result = 0;
for (let i = 0; i < num1; i++) {
for (let j = 0; j < num2; j++) {
result = i * j;
}
}
return result;
}
onmessage = function(e) {
const { a, b } = e.data;
const result = heavyFunction(a, b);
postMessage(result);
};
2. select option 20,000件が重いときに chunk で解消
selectタグ内に非常に多くのoption(例えば20,000件)がある場合、
これを一度にレンダリングするとパフォーマンスの問題が生じます。
これを解決するために、データをチャンク(小分け)にして、必要に応じて少量ずつレンダリングすることができます。これにより、描画時間を短縮し、UIの反応性を向上させることができます。
改善前:
<script setup>
import { ref } from 'vue';
const allOptions = ref([...Array(20000).keys()]); // 20,000件のダミーデータ
</script>
<template>
<select>
<option v-for="option in allOptions" :key="option" :value="option">
Option {{ option }}
</option>
</select>
</template>
改善後:
<script setup>
import { ref, computed } from 'vue';
const allOptions = ref([...Array(20000).keys()]); // 20,000件のダミーデータ
const chunkSize = 1000;
const currentChunkIndex = ref(0);
const currentOptions = computed(() => {
const start = currentChunkIndex.value * chunkSize;
const end = start + chunkSize;
return allOptions.value.slice(start, end);
});
</script>
<template>
<select>
<option v-for="option in currentOptions" :key="option" :value="option">
Option {{ option }}
</option>
</select>
</template>
3. debounceを使ってwatch内でのリクエスト送信を減らす
watchを使うとデータの変更に応じて処理を実行できますが、不適切に使用すると、多数のリクエストや計算が発生し、パフォーマンスが低下します。
debounce関数を用いることで、これらの処理の実行頻度を制御し、不必要なリクエストや計算を減少させることができます。
改善前:
<script setup>
import { ref, watch } from 'vue';
import axios from 'axios';
const searchText = ref('');
watch(searchText, (newVal) => {
axios.get('/search', { params: { text: newVal }});
});
</script>
<template>
<input v-model="searchText" placeholder="検索...">
</template>
改善後:
<script setup>
import { ref, watch } from 'vue';
import axios from 'axios';
import _ from 'lodash';
const searchText = ref('');
watch(searchText, _.debounce((newVal) => {
axios.get('/search', { params: { text: newVal }});
}, 500));
</script>
<template>
<input v-model="searchText" placeholder="検索...">
</template>
4. OffscreenCanvasでcanvas描画を軽量化
canvasを使用するアプリケーションでは、描画処理がパフォーマンスに大きな影響を及ぼすことがあります。OffscreenCanvasを使用することで、メインスレッドから描画処理を分離し、パフォーマンスを向上させることが可能です。これは、特にグラフィック処理が重要なアプリケーションにおいて、UIのスムーズな動作を実現するのに役立ちます。
改善前:
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// << Canvasの描画処理 >>
});
</script>
<template>
<canvas id="myCanvas"></canvas>
</template>
改善後:
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
const canvas = document.getElementById('myCanvas');
const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker(new URL('./my-canvas-worker.js', import.meta.url));
worker.postMessage({ canvas: offscreen }, [offscreen]);
});
</script>
<template>
<canvas id="myCanvas"></canvas>
</template>
// my-canvas-worker.js:
onmessage = function(e) {
const { canvas } = e.data;
const ctx = canvas.getContext('2d');
// << Canvasの描画処理 >>
};