Lima cara AirSHIFT meningkatkan performa runtime aplikasi React mereka

Studi kasus di dunia nyata tentang pengoptimalan performa React SPA.

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

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 sehari-hari. Tim engineer di Recruit Technologies melakukan project pemfaktoran ulang untuk meningkatkan salah satu aplikasi web mereka, AirSHIFT, guna meningkatkan performa input pengguna. Begini cara mereka melakukannya.

Respons lambat, produktivitas berkurang

AirSHIFT adalah aplikasi web desktop yang membantu pemilik toko, seperti restoran dan kafe, untuk mengelola pekerjaan 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.

Screenshot aplikasi web AirSHIFT.

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 sebuah studi riset pengguna, kami terkejut ketika salah satu pemilik toko mengatakan bahwa dia akan meninggalkan tempatnya untuk membuat kopi setelah mengklik tombol, hanya untuk menghabiskan waktu menunggu meja 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.

Indikator lingkaran berputar tanpa henti di perangkat kelas bawah.

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.

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

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: menyusun 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 shift. Aplikasi kini hanya memasang komponen dalam area pandang dan melepas komponen di luar layar.

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

Dalam hal ini, AirSHIFT menggunakan virtualisasi reaksi 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

Memvirtualisasi tabel saja mengurangi waktu pembuatan skrip sebanyak 6 detik (pada perlambatan CPU 4x + 3G cepat yang men-throttle lingkungan Macbook Pro). Ini adalah peningkatan performa yang paling berdampak dalam project pemfaktoran ulang.

Screenshot yang diberi anotasi dari rekaman panel Performa Chrome DevTools.
Sebelumnya: Sekitar 10 detik pembuatan skrip setelah input pengguna.
Screenshot lain yang dianotasi dari rekaman panel Performa Chrome DevTools.
Setelah: Skrip 4 detik setelah input pengguna.

2. Mengaudit 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 Waktu untuk menemukan logika yang tidak diperlukan yang berjalan di peristiwa siklus proses React.

Bagian Pengaturan waktu di panel Performa Chrome DevTools.
Peristiwa User Timing 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. Dengan memperbaikinya, Anda dapat 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 terbatas yang mereka pekerjakan sebagai uji coba, AirSHIFT menggeser sekitar 100 md JavaScript-nya dari thread utama ke thread pekerja (disimulasikan dengan throttling CPU 4x).

Screenshot rekaman panel Performance pada Chrome DevTools yang menunjukkan bahwa pembuatan skrip kini terjadi di web worker, bukan di thread utama.

AirSHIFT saat ini sedang mengeksplorasi apakah dapat memuat komponen lain secara lambat dan memindahkan lebih banyak logika ke pekerja web untuk lebih mengurangi jank.

4. Menetapkan anggaran performa

Setelah menerapkan 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 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 sekarang memantau peristiwa pemuatan tabel shift untuk memastikannya selesai dalam 3 detik untuk pengguna persentil ke-75. Untuk saat ini, anggaran ini tidak diterapkan, tetapi mereka mempertimbangkan notifikasi otomatis melalui Elasticsearch jika mereka melebihi anggaran.

Diagram yang menunjukkan bahwa persentil ke-75 selesai dalam waktu sekitar 2.500 mdtk, persentil ke-50 selesai dalam waktu sekitar 1.250 mdtk, persentil ke-25 selesai dalam waktu sekitar 750 mdtk, dan persentil ke-10 selesai dalam waktu sekitar 500 mdtk.
Dasbor Kibana yang menampilkan data performa harian berdasarkan persentil.

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. Eksperimen membutuhkan 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. 🔥

Foto hackathon.

Hasil

Pendekatan hackathon bekerja 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 mana 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.