Vue 3'te Performans ve Render Optimizasyonu Teknikleri
Vue 3 uygulamalarında performans, kullanıcı deneyimini doğrudan etkileyen kritik bir faktördür. Bu yazıda, Vue 3'ün sunduğu performans optimizasyon tekniklerini, render optimizasyonlarını ve büyük veri setleriyle çalışırken kullanabileceğimiz stratejileri inceleyeceğiz.
Virtual DOM ve Render Optimizasyonu
Vue 3'ün yeni render motoru, Virtual DOM implementasyonunda önemli iyileştirmeler getirdi. İşte bu optimizasyonları maksimum verimle kullanmanın yolları:
Template Compilation Optimizasyonları
<template> <!-- Kötü Kullanım --> <div v-if="show"> <ExpensiveComponent v-for="item in list" :key="item.id" /> </div> <!-- İyi Kullanım --> <template v-if="show"> <ExpensiveComponent v-for="item in list" :key="item.id" /> </template> </template> <script setup> import { defineComponent } from 'vue' // Gereksiz wrapper div'den kaçınmak için Fragment kullanımı defineComponent({ name: 'OptimizedList' }) </script>
Computed Properties ve Memorization
import { computed, ref } from 'vue' const list = ref([/* büyük veri listesi */]) const searchQuery = ref('') // Kötü Kullanım: Her render'da yeniden hesaplanır const filteredList = () => { return list.value.filter(item => item.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ) } // İyi Kullanım: Sadece bağımlılıklar değiştiğinde hesaplanır const optimizedFilteredList = computed(() => { return list.value.filter(item => item.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ) }) // Çok parametreli hesaplamalar için custom memorization function useMemoize(fn: Function) { const cache = new Map() return (...args: any[]) => { const key = JSON.stringify(args) if (cache.has(key)) return cache.get(key) const result = fn(...args) cache.set(key, result) return result } }
Büyük Listelerin Optimizasyonu
Büyük veri setleriyle çalışırken performansı korumak için virtual scrolling ve chunk rendering teknikleri:
Virtual Scrolling Implementation
<template> <div class="virtual-list" :style="containerStyle"> <div class="virtual-list-inner" :style="innerStyle"> <template v-for="item in visibleItems" :key="item.id"> <div class="list-item" :style="{ height: itemHeight + 'px' }"> {{ item.content }} </div> </template> </div> </div> </template> <script setup lang="ts"> import { computed, ref, onMounted, onUnmounted } from 'vue' const props = defineProps<{ items: Array<{ id: number; content: string }> itemHeight: number }>() const scrollTop = ref(0) const containerHeight = ref(0) const containerRef = ref<HTMLElement | null>(null) // Görünür öğeleri hesapla const visibleItems = computed(() => { const start = Math.floor(scrollTop.value / props.itemHeight) const count = Math.ceil(containerHeight.value / props.itemHeight) return props.items.slice(start, start + count + 1) }) const containerStyle = computed(() => ({ height: `${containerHeight.value}px`, overflow: 'auto', position: 'relative' })) const innerStyle = computed(() => ({ height: `${props.items.length * props.itemHeight}px`, transform: `translateY(${Math.floor(scrollTop.value / props.itemHeight) * props.itemHeight}px)` })) const handleScroll = () => { if (containerRef.value) { scrollTop.value = containerRef.value.scrollTop } } onMounted(() => { if (containerRef.value) { containerHeight.value = containerRef.value.clientHeight containerRef.value.addEventListener('scroll', handleScroll) } }) onUnmounted(() => { if (containerRef.value) { containerRef.value.removeEventListener('scroll', handleScroll) } }) </script> <style scoped> .virtual-list { position: relative; overflow: auto; } .virtual-list-inner { position: absolute; top: 0; left: 0; width: 100%; } .list-item { padding: 8px; border-bottom: 1px solid #eee; } </style>
Chunk Rendering
Büyük listeleri parçalar halinde render etme:
import { ref, onMounted } from 'vue' export function useChunkRendering<T>(items: T[], chunkSize = 100) { const renderedItems = ref<T[]>([]) const currentChunk = ref(0) const renderNextChunk = () => { const start = currentChunk.value * chunkSize const chunk = items.slice(start, start + chunkSize) renderedItems.value = [...renderedItems.value, ...chunk] currentChunk.value++ } const observer = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { renderNextChunk() } }) onMounted(() => { renderNextChunk() // İlk chunk'ı render et }) return { renderedItems, renderNextChunk } } // Kullanımı const items = ref([/* büyük veri listesi */]) const { renderedItems, renderNextChunk } = useChunkRendering(items.value)
Component Render Optimizasyonu
defineAsyncComponent ile Lazy Loading
import { defineAsyncComponent } from 'vue' // Ağır componenti lazy load et const HeavyComponent = defineAsyncComponent(() => import('./components/HeavyComponent.vue') ) // Yükleme durumu ve hata yönetimi ile const HeavyComponentWithOptions = defineAsyncComponent({ loader: () => import('./components/HeavyComponent.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorComponent, delay: 200, timeout: 3000 })
shallowRef ve shallowReactive Kullanımı
Derin reaktivite gerektirmeyen durumlarda performans optimizasyonu:
import { shallowRef, shallowReactive } from 'vue' // Sadece üst seviye değişiklikleri izle const state = shallowReactive({ user: { profile: { name: 'John', settings: { /* derin nested veriler */ } } } }) // Büyük veri yapıları için shallow referans const bigData = shallowRef({ // Çok büyük nested veri yapısı }) // Sadece referans değiştiğinde yeniden render bigData.value = newBigData
Event Handling Optimizasyonu
Event Debouncing ve Throttling
import { ref } from 'vue' export function useDebounce<T extends (...args: any[]) => any>( fn: T, delay: number ) { let timeout: NodeJS.Timeout return (...args: Parameters<T>) => { clearTimeout(timeout) timeout = setTimeout(() => fn(...args), delay) } } // Kullanımı const searchQuery = ref('') const debouncedSearch = useDebounce((query: string) => { // API çağrısı yap fetchSearchResults(query) }, 300) // Template'de // <input v-model="searchQuery" @input="debouncedSearch(searchQuery)" />
Memory Leak Önleme
Composition API ile Cleanup
import { onUnmounted, onMounted } from 'vue' export function useEventListener( target: Window | HTMLElement, event: string, callback: EventListener ) { onMounted(() => target.addEventListener(event, callback)) // Cleanup onUnmounted(() => target.removeEventListener(event, callback)) } // WebSocket bağlantıları için cleanup örneği export function useWebSocket(url: string) { const ws = new WebSocket(url) onUnmounted(() => { ws.close() }) return ws }
Performance Monitoring
Custom Performance Metrics
import { onMounted, onUpdated } from 'vue' export function usePerformanceMonitoring(componentName: string) { let startTime: number onMounted(() => { startTime = performance.now() // Component mount süresini ölç requestAnimationFrame(() => { const mountTime = performance.now() - startTime console.log(`${componentName} mount time:`, mountTime) }) }) onUpdated(() => { const updateTime = performance.now() - startTime console.log(`${componentName} update time:`, updateTime) }) }
Sonuç
Vue 3'te performans optimizasyonu, birçok farklı teknik ve yaklaşımın bir kombinasyonudur. Virtual DOM optimizasyonları, computed properties'in doğru kullanımı, büyük listelerin verimli yönetimi ve component lazy loading gibi tekniklerin uygun şekilde kullanılması, uygulamanızın performansını önemli ölçüde artırabilir.
Bu optimizasyon tekniklerini uygularken, her zaman önce performans ölçümü yapmanız ve gerçekten bir optimizasyona ihtiyaç olup olmadığını belirlemeniz önemlidir. Erken optimizasyon, kod karmaşıklığını artırabilir ve bakım maliyetlerini yükseltebilir.
İlgili Etiketler: #Vuejs #Performance #Optimization #VirtualDOM #CompositionAPI #Frontend #JavaScript #WebDevelopment