Lima cara AirSHIFT meningkatkan performa runtime aplikasi React mereka

Studi kasus nyata tentang pengoptimalan performa React SPA.

Kento Tsuji
Kento Tsuji
Satoshi Arai
Satoshi Arai
Yusuke Utsunomiya
Yusuke Utsunomiya
Yosuke Furukawa
Yosuke Furukawa

Performa situs web bukan hanya tentang waktu muat. Memberikan pengalaman yang cepat dan responsif kepada pengguna sangatlah penting, terutama untuk aplikasi desktop produktivitas yang digunakan orang setiap hari. Tim engineer di Recruit Technologies menjalani project pemfaktoran ulang untuk meningkatkan salah satu aplikasi web mereka, AirSHIFT, untuk meningkatkan performa input pengguna. Begini cara mereka melakukannya.

Respons lambat, produktivitas lebih rendah

AirSHIFT adalah aplikasi web desktop yang membantu pemilik toko, seperti restoran dan kafe, untuk mengelola shift kerja anggota staf mereka. Dibuat dengan React, aplikasi web satu halaman ini menyediakan fitur klien yang lengkap, termasuk berbagai tabel petak jadwal shift yang diatur berdasarkan hari, minggu, bulan, dan lainnya.

Screenshot aplikasi web AirSHIFT.

Saat tim engineering Recruit Technologies menambahkan fitur baru ke aplikasi AirSHIFT, mereka mulai melihat lebih banyak masukan seputar performa yang lambat. Manajer teknik AirSHIFT, Yosuke Furukawa, mengatakan:

Dalam sebuah studi riset pengguna, kami terkejut ketika salah satu pemilik toko mengatakan dia akan meninggalkan tempat duduknya untuk menyeduh kopi setelah mengklik tombol, hanya untuk menghabiskan waktu menunggu meja shift dimuat.

Setelah melakukan penelitian, tim teknik menyadari bahwa banyak pengguna mereka mencoba memuat tabel shift besar pada komputer spesifikasi rendah, seperti laptop Celeron M 1 GHz dari 10 tahun yang lalu.

Indikator lingkaran berputar tanpa batas di perangkat kelas bawah.

Aplikasi AirSHIFT memblokir thread utama dengan skrip yang mahal, tetapi tim engineer tidak menyadari betapa mahalnya skrip tersebut karena mengembangkan dan melakukan pengujian pada komputer berspesifikasi kaya dengan koneksi Wi-Fi yang cepat.

Diagram yang menunjukkan aktivitas runtime aplikasi.
Saat memuat tabel shift, sekitar 80% waktu pemuatan dihabiskan untuk menjalankan skrip.

Setelah membuat profil performa di Chrome DevTools dengan throttling CPU dan jaringan yang diaktifkan, menjadi 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: membangun DOM virtual dan merendernya di layar secara proporsional dengan jumlah anggota staf dan slot waktu. Misalnya, jika sebuah restoran memiliki 50 anggota yang bekerja dan ingin memeriksa jadwal shift bulanan mereka, tabelnya adalah tabel 50 (anggota) dikalikan 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 penelitian mereka mengetahui ada toko yang mengelola 200 anggota staf, yang membutuhkan sekitar 6.000 komponen sel dalam satu tabel bulanan.

Untuk mengurangi biaya operasi ini, AirSHIFT memvirtualisasikan tabel shift. Aplikasi sekarang hanya memasang komponen dalam area pandang dan melepaskan komponen di luar layar.

Screenshot beranotasi yang menunjukkan bahwa AirSHIFT digunakan untuk merender konten di luar area pandang.
Sebelum: Merender semua sel tabel shift.
Screenshot beranotasi yang menunjukkan bahwa AirSHIFT sekarang hanya merender konten yang terlihat di area pandang.
Sesudah: Hanya merender sel dalam area tampilan.

Dalam hal ini, AirSHIFT menggunakan react-virtualisasi karena ada persyaratan untuk mengaktifkan tabel petak dua dimensi yang kompleks. Mereka juga sedang mempelajari cara mengonversi implementasi untuk menggunakan react-window ringan di masa mendatang.

Hasil

Virtualisasi pada tabel saja mengurangi waktu pembuatan skrip hingga 6 detik (pada pelambatan CPU 4x + Fast 3G yang dibatasi lingkungan Macbook Pro). Ini adalah peningkatan performa yang paling berdampak dalam project pemfaktoran ulang.

Screenshot yang dianotasi dari rekaman panel Performa Chrome DevTools.
Sebelum: Sekitar 10 detik pembuatan skrip setelah input pengguna.
Screenshot lain yang dianotasi dari rekaman panel Performance Chrome DevTools.
Setelah: 4 detik pembuatan skrip setelah input pengguna.

2. Mengaudit dengan User Timing API

Selanjutnya, tim AirSHIFT memfaktorkan ulang skrip yang berjalan pada input pengguna. flame chart Chrome DevTools memungkinkan untuk menganalisis apa yang sebenarnya terjadi di thread utama. Namun, tim AirSHIFT merasa lebih mudah menganalisis aktivitas aplikasi berdasarkan siklus proses React.

React 16 menyediakan trace performanya melalui User Timing API, yang dapat Anda visualisasikan dari bagian Waktu Chrome DevTools. AirSHIFT menggunakan bagian Waktu untuk menemukan logika yang tidak diperlukan yang berjalan dalam peristiwa siklus proses React.

Bagian Timings pada panel Performance di Chrome DevTools.
Peristiwa Waktu Pengguna React.

Hasil

Tim AirSHIFT menemukan bahwa Rekonsiliasi Pohon React yang tidak perlu terjadi tepat sebelum setiap navigasi rute. Ini berarti bahwa React memperbarui tabel shift secara tidak perlu sebelum navigasi. Pembaruan status Redux yang tidak perlu menyebabkan masalah ini. Memperbaikinya akan menghemat waktu pembuatan skrip sekitar 750 milidetik. AirSHIFT juga melakukan pengoptimalan mikro lainnya yang pada akhirnya menghasilkan total 1 detik pengurangan waktu pembuatan skrip.

3. Komponen pemuatan lambat dan memindahkan logika mahal ke pekerja web

AirSHIFT memiliki aplikasi obrolan bawaan. Banyak pemilik toko berkomunikasi dengan anggota staf mereka melalui chat sambil melihat tabel shift, yang berarti bahwa pengguna mungkin mengetik pesan saat tabel sedang dimuat. Jika thread utama ditempati dengan skrip yang merender tabel, input pengguna dapat mengalami jank.

Untuk meningkatkan pengalaman ini, AirSHIFT kini menggunakan React.lazy dan Suspense guna menampilkan placeholder untuk isi tabel sambil memuat komponen sebenarnya dengan lambat.

Tim AirSHIFT juga memigrasikan beberapa logika bisnis yang mahal dalam komponen yang dimuat dengan lambat ke pekerja web. Cara ini mengatasi masalah jank input pengguna dengan mengosongkan thread utama sehingga dapat berfokus dalam merespons input pengguna.

Biasanya developer menghadapi kompleksitas dalam menggunakan pekerja, tetapi kali ini Comlink melakukan bagian pekerjaan yang sulit bagi mereka. Di bawah ini adalah kode pseudo tentang cara AirSHIFT menangani salah satu operasi paling mahal yang mereka miliki: 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 calc

/** 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>;
}

Mengimplementasikan logika penghitungan yang berjalan di pekerja dan menampilkannya 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 kerjakan sebagai uji coba terbatas, AirSHIFT mengalihkan sekitar 100 md JavaScript-nya dari thread utama ke thread pekerja (disimulasikan dengan throttling CPU 4x).

Screenshot rekaman panel Performa Chrome DevTools yang menunjukkan bahwa pembuatan skrip kini terjadi di pekerja web, bukan di thread utama.

AirSHIFT saat ini sedang mempelajari apakah mereka dapat menjalankan lambat pada komponen lain dan mengalihkan lebih banyak logika ke pekerja web untuk semakin mengurangi jank.

4. Menetapkan anggaran performa

Setelah mengimplementasikan semua pengoptimalan ini, penting untuk memastikan 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 bahkan dalam kondisi yang tidak ideal.

  • Waktu penyelesaian skrip untuk setiap peristiwa Redux sekarang diukur
  • Data performa dikumpulkan di Elasticsearch
  • Performa persentil ke-10, ke-25, ke-50, dan ke-75 dari setiap peristiwa divisualisasikan dengan Kibana

AirSHIFT kini memantau peristiwa pemuatan tabel shift untuk memastikannya selesai dalam waktu 3 detik untuk pengguna persentil ke-75. Anggaran ini belum diterapkan untuk saat ini, tetapi mereka mempertimbangkan notifikasi otomatis melalui Elasticsearch jika melebihi anggaran.

Sebuah diagram menunjukkan bahwa persentil ke-75 selesai dalam waktu sekitar 2500 md, persentil ke-50 dalam sekitar 1250 md, persentil ke-25 dalam sekitar 750 md, dan persentil ke-10 dalam sekitar 500 md.
Dasbor Kibana menampilkan data performa harian berdasarkan persentil.

Hasil

Dari grafik di atas, Anda dapat mengetahui bahwa AirSHIFT sekarang sebagian besar mencapai anggaran 3 detik untuk pengguna persentil ke-75 dan juga memuat tabel shift dalam satu detik untuk pengguna persentil ke-25. Dengan merekam 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 bagi tim engineering dan bisnis untuk memprioritaskan pengembangan non-fungsional. Sebagian tantangannya adalah beberapa pengoptimalan performa ini tidak dapat direncanakan. Mereka membutuhkan eksperimen dan pola pikir coba-coba.

AirSHIFT kini melakukan hackathon performa internal selama 1 hari agar engineer dapat berfokus hanya pada pekerjaan terkait performa. Dalam hackathon ini, mereka menghilangkan semua kendala dan menghormati kreativitas para engineer, yang berarti setiap implementasi yang berkontribusi pada kecepatan patut dipertimbangkan. Untuk mempercepat hackathon, AirSHIFT membagi grup menjadi tim-tim kecil dan setiap tim bersaing untuk melihat siapa yang bisa mendapatkan peningkatan skor performa Lighthouse terbesar. Tim menjadi sangat kompetitif! 🔥

Foto hackathon.

Hasil

Mereka berhasil menggunakan pendekatan hackathon.

  • Hambatan performa dapat mudah dideteksi dengan benar-benar mencoba beberapa pendekatan selama hackathon dan mengukur masing-masing dengan Lighthouse.
  • Setelah hackathon, agak mudah untuk meyakinkan tim pengoptimalan mana yang harus mereka prioritaskan untuk rilis produksi.
  • Ini juga merupakan cara yang efektif untuk menyampaikan pentingnya kecepatan. Setiap peserta dapat memahami korelasi antara cara Anda membuat kode dan bagaimana hal itu menghasilkan kinerja.

Efek samping yang bagus adalah banyak tim teknik lain di dalam Recruit tertarik dengan pendekatan langsung ini dan tim AirSHIFT sekarang memfasilitasi beberapa hackathon kecepatan dalam perusahaan.

Ringkasan

Ini jelas bukan perjalanan termudah bagi AirSHIFT untuk mengerjakan pengoptimalan ini, tetapi hal itu jelas membuahkan hasil. Sekarang AirSHIFT memuat tabel shift dalam median 1,5 detik yang merupakan peningkatan 6x dari performa mereka sebelum proyek dimulai.

Setelah pengoptimalan performa diluncurkan, salah satu pengguna mengatakan:

Terima kasih banyak telah mempercepat pemuatan tabel shift. Mengatur pekerjaan {i>shift<i} kini jauh lebih efisien.