Studi kasus di dunia nyata tentang pengoptimalan performa React SPA.
Performa situs bukan hanya tentang waktu pemuatan. Sangat penting untuk memberikan pengalaman yang cepat dan responsif kepada pengguna, terutama untuk aplikasi desktop produktivitas yang digunakan orang setiap hari. Tim engineer di Recruit Technologies melakukan project pemfaktoran ulang untuk meningkatkan salah satu aplikasi web mereka, AirSHIFT, guna meningkatkan performa input pengguna. Berikut cara mereka melakukannya.
Respons lambat, produktivitas berkurang
AirSHIFT adalah aplikasi web desktop yang membantu pemilik toko, seperti restoran dan kafe, untuk mengelola kerja shift anggota staf mereka. Dibuat dengan React, aplikasi web satu halaman ini menyediakan fitur klien yang kaya, termasuk berbagai tabel petak jadwal shift yang diatur berdasarkan hari, minggu, bulan, dan lainnya.
Saat tim engineer Recruit Technologies menambahkan fitur baru ke aplikasi AirSHIFT, mereka mulai melihat lebih banyak masukan terkait performa lambat. Manajer engineering AirSHIFT, Yosuke Furukawa, mengatakan:
Dalam studi riset pengguna, kami terkejut saat salah satu pemilik toko mengatakan bahwa dia akan meninggalkan kursinya untuk menyeduh kopi setelah mengklik tombol, hanya untuk menghabiskan waktu menunggu tabel shift dimuat.
Setelah melakukan riset, tim engineer menyadari bahwa banyak pengguna mereka mencoba memuat tabel pergeseran besar di komputer dengan spesifikasi rendah, seperti laptop Celeron M 1 GHz dari 10 tahun yang lalu.
Aplikasi AirSHIFT memblokir thread utama dengan skrip yang mahal, tetapi tim engineer tidak menyadari betapa mahalnya skrip tersebut karena mereka mengembangkan dan menguji di komputer dengan spesifikasi lengkap dan koneksi Wi-Fi yang cepat.
Setelah membuat profil performanya di Chrome DevTools dengan CPU dan throttling jaringan diaktifkan, jelas bahwa pengoptimalan performa diperlukan. AirSHIFT membentuk satuan tugas untuk mengatasi masalah ini. Berikut adalah 5 hal yang mereka fokuskan untuk membuat aplikasi mereka lebih responsif terhadap input pengguna.
1. Memvirtualisasi tabel besar
Menampilkan tabel shift memerlukan beberapa langkah yang mahal: membuat DOM virtual dan merendernya di layar sesuai dengan jumlah anggota staf dan slot waktu. Misalnya, jika restoran memiliki 50 anggota yang bekerja dan ingin memeriksa jadwal shift bulanan mereka, tabel tersebut akan berisi 50 (anggota) dikalikan dengan 30 (hari) yang akan menghasilkan 1.500 komponen sel untuk dirender. Ini adalah operasi yang sangat mahal, terutama untuk perangkat dengan spesifikasi rendah. Kenyataannya, keadaannya lebih buruk. Dari riset tersebut, mereka mengetahui bahwa ada toko yang mengelola 200 anggota staf,yang memerlukan sekitar 6.000 komponen sel dalam satu tabel bulanan.
Untuk mengurangi biaya operasi ini, AirSHIFT memvirtualisasi tabel pergeseran. Aplikasi kini hanya memasang komponen dalam area pandang dan melepas komponen di luar layar.
Dalam hal ini, AirSHIFT menggunakan react-virtualized karena ada persyaratan untuk mengaktifkan tabel petak dua dimensi yang kompleks. Mereka juga mempelajari cara mengonversi implementasi untuk menggunakan react-window yang ringan di masa mendatang.
Hasil
Virtualisasi tabel saja mengurangi waktu pembuatan skrip sebesar 6 detik (pada pelambatan CPU 4x + lingkungan Macbook Pro yang di-throttle 3G Cepat). Ini adalah peningkatan performa yang paling berdampak dalam project pemfaktoran ulang.
2. Melakukan audit dengan User Timing API
Selanjutnya, tim AirSHIFT memfaktorkan ulang skrip yang berjalan pada input pengguna. Diagram api Chrome DevTools memungkinkan Anda menganalisis apa yang sebenarnya terjadi di thread utama. Namun, tim AirSHIFT merasa lebih mudah untuk menganalisis aktivitas aplikasi berdasarkan siklus proses React.
React 16 menyediakan trace performanya melalui User Timing API, yang dapat Anda visualisasikan dari bagian Timings Chrome DevTools. AirSHIFT menggunakan bagian Timings untuk menemukan logika yang tidak perlu yang berjalan dalam peristiwa siklus proses React.
Hasil
Tim AirSHIFT menemukan bahwa React Tree Reconciliation yang tidak perlu terjadi tepat sebelum setiap navigasi rute. Artinya, React memperbarui tabel pergeseran secara tidak perlu sebelum navigasi. Update status Redux yang tidak perlu menyebabkan masalah ini. Memperbaikinya menghemat waktu pembuatan skrip sekitar 750 md. AirSHIFT juga melakukan pengoptimalan mikro lainnya yang pada akhirnya menyebabkan pengurangan total waktu pembuatan skrip sebesar 1 detik.
3. Memuat komponen secara lambat dan memindahkan logika yang mahal ke web worker
AirSHIFT memiliki aplikasi chat bawaan. Banyak pemilik toko berkomunikasi dengan anggota staf mereka melalui chat sambil melihat tabel shift, yang berarti pengguna mungkin mengetik pesan saat tabel sedang dimuat. Jika thread utama dipenuhi dengan skrip yang merender tabel, input pengguna dapat mengalami jank.
Untuk meningkatkan pengalaman ini, AirSHIFT kini menggunakan React.lazy dan Suspense untuk menampilkan placeholder konten tabel sambil memuat komponen sebenarnya secara lambat.
Tim AirSHIFT juga memigrasikan beberapa logika bisnis yang mahal dalam komponen yang dimuat lambat ke web worker. Hal ini menyelesaikan masalah jank input pengguna dengan mengosongkan thread utama sehingga dapat berfokus untuk merespons input pengguna.
Biasanya developer menghadapi kompleksitas dalam menggunakan pekerja, tetapi kali ini Comlink melakukan pekerjaan berat untuk mereka. Berikut adalah kode pseudo tentang cara AirSHIFT menjadikan salah satu operasi termahal mereka sebagai pekerja: menghitung total biaya tenaga kerja.
Di App.js, gunakan React.lazy dan Suspense untuk menampilkan konten penggantian saat memuat
/** App.js */
import React, { lazy, Suspense } from 'react'
// Lazily loading the Cost component with React.lazy
const Hello = lazy(() => import('./Cost'))
const Loading = () => (
<div>Some fallback content to show while loading</div>
)
// Showing the fallback content while loading the Cost component by Suspense
export default function App({ userInfo }) {
return (
<div>
<Suspense fallback={<Loading />}>
<Cost />
</Suspense>
</div>
)
}
Di komponen Biaya, gunakan comlink untuk menjalankan logika penghitungan
/** Cost.js */
import React from 'react';
import { proxy } from 'comlink';
// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default async function Cost({ userInfo }) {
// execute the calculation in the worker
const instance = await new WorkerlizedCostCalc();
const cost = await instance.calc(userInfo);
return <p>{cost}</p>;
}
Menerapkan logika penghitungan yang berjalan di pekerja dan mengeksposnya dengan comlink
// WorkerlizedCostCalc.js
import { expose } from 'comlink'
import { someExpensiveCalculation } from './CostCalc.js'
// Expose the new workerlized calc function with comlink
expose({
calc(userInfo) {
// run existing (expensive) function in the worker
return someExpensiveCalculation(userInfo);
}
}, self);
Hasil
Meskipun jumlah logika yang mereka jadikan pekerja terbatas sebagai uji coba, AirSHIFT memindahkan sekitar 100 md JavaScript dari thread utama ke thread pekerja (disimulasikan dengan throttling CPU 4x).
AirSHIFT saat ini sedang mempelajari apakah mereka dapat memuat lambat komponen lain dan mentransfer lebih banyak logika ke pekerja web untuk lebih mengurangi jank.
4. Menetapkan anggaran performa
Setelah menerapkan semua pengoptimalan ini, sangat penting untuk memastikan bahwa aplikasi tetap berperforma baik dari waktu ke waktu. AirSHIFT kini menggunakan bundlesize agar tidak melebihi ukuran file JavaScript dan CSS saat ini. Selain menetapkan anggaran dasar ini, mereka membuat dasbor untuk menampilkan berbagai persentil waktu pemuatan tabel shift guna memeriksa apakah aplikasi berperforma baik bahkan dalam kondisi yang tidak ideal.
- Waktu penyelesaian skrip untuk setiap peristiwa Redux kini diukur
- Data performa dikumpulkan di Elasticsearch
- Performa persentil ke-10, ke-25, ke-50, dan ke-75 dari setiap peristiwa divisualisasi dengan Kibana
AirSHIFT kini memantau peristiwa pemuatan tabel shift untuk memastikan peristiwa tersebut selesai dalam 3 detik bagi pengguna persentil ke-75. Untuk saat ini, anggaran ini tidak diterapkan, tetapi mereka mempertimbangkan notifikasi otomatis melalui Elasticsearch jika mereka melebihi anggaran.
Hasil
Dari grafik di atas, Anda dapat mengetahui bahwa AirSHIFT kini sebagian besar mencapai anggaran 3 detik untuk pengguna persentil ke-75 dan juga memuat tabel shift dalam waktu satu detik untuk pengguna persentil ke-25. Dengan mengambil data performa RUM dari berbagai kondisi dan perangkat, AirSHIFT kini dapat memeriksa apakah rilis fitur baru benar-benar memengaruhi performa aplikasi atau tidak.
5. Hackathon performa
Meskipun semua upaya pengoptimalan performa ini penting dan berdampak, tidak selalu mudah untuk membuat tim engineering dan bisnis memprioritaskan pengembangan non-fungsional. Salah satu tantangannya adalah beberapa pengoptimalan performa ini tidak dapat direncanakan. Hal ini memerlukan eksperimen dan pola pikir coba-coba.
AirSHIFT kini mengadakan hackathon performa internal selama 1 hari agar engineer hanya berfokus pada pekerjaan terkait performa. Dalam hackathon ini, mereka menghapus semua batasan dan menghargai kreativitas engineer, yang berarti setiap implementasi yang berkontribusi pada kecepatan layak dipertimbangkan. Untuk mempercepat hackathon, AirSHIFT membagi grup menjadi tim kecil dan setiap tim bersaing untuk melihat siapa yang bisa mendapatkan peningkatan skor performa Lighthouse terbesar. Tim-tim menjadi sangat kompetitif. 🔥
Hasil
Pendekatan hackathon berfungsi dengan baik untuk mereka.
- Bottleneck performa dapat dengan mudah dideteksi dengan benar-benar mencoba beberapa pendekatan selama hackathon dan mengukur setiap pendekatan dengan Lighthouse.
- Setelah hackathon, cukup mudah untuk meyakinkan tim tentang pengoptimalan yang harus diprioritaskan untuk rilis produksi.
- Ini juga merupakan cara yang efektif untuk mendukung pentingnya kecepatan. Setiap peserta dapat memahami korelasi antara cara Anda membuat kode dan pengaruhnya terhadap performa.
Efek samping yang baik adalah banyak tim engineer lain di Recruit yang tertarik dengan pendekatan langsung ini dan tim AirSHIFT kini memfasilitasi beberapa hackathon cepat di dalam perusahaan.
Ringkasan
Ini jelas bukan perjalanan termudah bagi AirSHIFT untuk mengerjakan pengoptimalan ini, tetapi hasilnya sangat memuaskan. Sekarang AirSHIFT memuat tabel shift dalam median 1,5 detik, yang merupakan peningkatan 6x dari performanya sebelum project.
Setelah pengoptimalan performa diluncurkan, seorang pengguna mengatakan:
Terima kasih banyak telah membuat tabel shift dimuat dengan cepat. Mengatur kerja shift kini jauh lebih efisien.