Pernah kena bug race condition pas fetch data yuk kita pahami solusinya

Pernah kena bug race condition pas fetch data yuk kita pahami solusinya
Photo by Ahmad Hanif/Unsplash

Bayangkan kita lagi asik ngetik di kolom pencarian aplikasi web kesayangan. Kita berniat mencari produk sepatu, lalu dengan cepat kita sadar bahwa kita lebih butuh baju. Tanpa ragu kita menghapus tulisan sepatu lalu mengetik baju secara cepat. Namun beberapa detik kemudian kejadian aneh muncul. Tampilan di layar malah menunjukkan daftar sepatu padahal di kolom pencarian sudah jelas tertulis baju. Kejadian mengesalkan ini membuat kita bertanya tanya apakah ada yang salah dengan koneksi internet atau ada hantu di dalam kode kita. Pengalaman ini adalah contoh sangat nyata dari bug race condition saat melakukan fetching data. Fenomena ini sering sekali membuat para pengembang aplikasi merenung di malam hari sambil mencari tahu penyebab pastinya. Buat kita para pengembang web, bug ini ibarat teka teki yang membingungkan karena semua kode async terasa sudah ditulis dengan benar. Dalam artikel ini kita bakal menyelami fenomena race condition secara mendalam lengkap dengan solusi praktis yang bisa langsung kita terapkan hari ini juga.

Mengapa Bug Race Condition Sering Bikin Kita Pusing

Race condition pada dasarnya adalah situasi di mana dua atau lebih proses berjalan secara asynchronous dan hasil akhirnya sangat tergantung pada proses mana yang selesai lebih dulu. Ketika kita melakukan fetching data dari server, kita tidak pernah bisa menjamin jawaban server mana yang akan sampai duluan ke browser pengguna.

Jaringan internet itu sangat dinamis dan penuh misteri. Request pertama yang kita kirim buat kata kunci sepatu mungkin mengalami kendala koneksi sehingga butuh waktu dua detik buat kembali. Sementara request kedua buat kata kunci baju diproses sangat cepat oleh server dan kembali hanya dalam waktu setengah detik. Karena request kedua selesai lebih cepat, data baju tampil duluan di layar. Namun tidak lama setelah itu request pertama baru saja sampai. Sistem aplikasi kita yang polos tanpa penanganan khusus akan langsung menimpa data baju dengan data sepatu yang baru datang belakangan.

Hasil akhirnya adalah kondisi state aplikasi yang kacau balau. Teks input menunjukkan baju namun data yang tampil adalah sepatu. Masalah ini sangat membingungkan pengguna dan bisa merusak reputasi aplikasi yang sedang kita bangun bersama.

Skenario Nyata Yang Sangat Sering Kita Temui

Bug ini tidak cuma hadir di fitur pencarian saja. Ada banyak skenario dalam pengembangan aplikasi modern yang rawan terkena jebakan race condition. Kita perlu mengenali pola pola ini agar bisa lebih waspada saat menulis kode.

Skenario pertama adalah fitur filter produk di ecommerce. Ketika pengguna dengan cepat mengubah filter dari harga terendah ke harga tertinggi lalu berpindah lagi ke produk terpopuler dalam hitungan detik. Jika setiap klik memicu request baru tanpa membatalkan request lama, data yang muncul di layar bisa acak acakan sesuai urutan selesainya request dari jaringan.

Skenario kedua terjadi pada navigasi halaman atau perpindahan tab dashboard. Bayangkan pengguna mengklik tab profil lalu dengan cepat berpindah ke tab pengaturan. Jika request data profil memakan waktu lama dan baru selesai ketika pengguna sudah berada di tab pengaturan, informasi profil bisa saja tiba tiba muncul di halaman pengaturan.

Skenario ketiga ada pada fitur simpan otomatis atau auto save pada aplikasi catatan online. Jika pengguna mengetik terus menerus dan proses penyimpanan berjalan di latar belakang, urutan penyimpanan yang terbalik bisa menghapus kata kata terbaru dan menggantinya dengan versi catatan yang lebih lama.

Solusi Pertama Memanfaatkan AbortController Yang Super Canggih

Salah satu cara paling bersih dan modern buat mengatasi race condition adalah dengan menghentikan request lama yang sedang berjalan sebelum kita membuat request baru. Browser modern sudah menyediakan fitur bawaan bernama AbortController yang sangat sakti buat urusan ini.

Dengan AbortController kita bisa membuat sebuah sinyal pembatalan. Sinyal ini kita selipkan ke dalam request fetch yang kita kirim. Ketika pengguna mengetik kata baru atau memicu request baru, kita tinggal memanggil fungsi abort pada controller lama. Secara otomatis browser akan menghentikan request yang sedang berlangsung di jaringan sehingga responnya tidak akan pernah diproses lebih lanjut oleh aplikasi kita.

Penggunaan AbortController ini sangat sederhana dan tidak membutuhkan library tambahan apapun. Kita cukup menyimpan referensi controller di dalam variabel atau useRef jika kita memakai React. Setiap kali fungsi fetch dipanggil, kita cek apakah controller sebelumnya masih ada. Jika ada kita panggil fungsi abort lalu kita buat controller baru. Hal ini memastikan hanya request paling terakhir yang dibiarkan hidup sampai selesai.

Proses pembatalan ini juga sangat menghemat resource jaringan karena browser langsung memutuskan koneksi untuk request yang sudah tidak dibutuhkan lagi. Pengalaman pengguna pun jadi terasa jauh lebih responsif dan asik.

Solusi Kedua Menahan Input Pengguna Dengan Teknik Debounce

Selain membatalkan request yang sedang berjalan, kita juga bisa mencegah request dikirim terlalu sering saat pengguna sedang aktif melakukan input. Teknik ini dikenal dengan nama debounce.

Debounce bekerja dengan cara memberikan jeda waktu tunggu setelah pengguna berhenti mengetik. Misalnya kita mengatur jeda waktu selama tiga ratus milidetik. Setiap kali pengguna mengetik satu huruf, timer akan dihitung ulang dari awal. Request fetching data baru benar benar akan dikirimkan ke server setelah pengguna berhenti mengetik selama minimal tiga ratus milidetik.

Dengan menerapkan debounce kita bisa mengurangi jumlah request yang dikirim ke server secara drastis. Jika pengguna mengetik sepuluh huruf dalam satu detik, tanpa debounce akan ada sepuluh request yang meluncur ke server secara berurutan. Namun dengan debounce hanya akan ada satu request yang dikirim yaitu setelah pengguna selesai mengetik seluruh kata tersebut.

Teknik debounce ini sangat ampuh dipadukan dengan AbortController. Debounce bertugas menekan jumlah request di awal, sedangkan AbortController memastikan urutan request yang lolos tetap berjalan sesuai ekspektasi tanpa bentrokan data.

Solusi Ketiga Menggunakan Flagging Dan Verifikasi ID Request

Jika karena alasan tertentu kita tidak bisa menggunakan AbortController, misalnya saat menggunakan pustaka koneksi lama yang belum mendukung sinyal pembatalan, kita masih bisa memakai strategi flagging atau perbandingan id request.

Prinsip dari solusi ini adalah memberikan penanda unik pada setiap request yang kita buat, misalnya berupa angka acak atau timestamp waktu saat request dipicu. Kita juga menyimpan id request paling terakhir di dalam variabel state aplikasi kita.

Ketika respon dari server akhirnya kembali, sebelum kita mengupdate state tampilan kita lakukan verifikasi terlebih dahulu. Kita bandingkan id dari respon yang baru tiba dengan id request terbaru yang tersimpan di state. Jika id respon tersebut ternyata lebih lama dari id request terbaru, maka respon tersebut langsung kita buang dan abaikan begitu saja.

Meskipun request lama tetap berjalan sampai selesai dan menghabiskan bandwidth internet, cara verifikasi ini tetap efektif mencegah data lama menimpa data terbaru di layar pengguna. Tampilan aplikasi kita akan tetap konsisten dan akurat.

Solusi Keempat Mengandalkan Library Data Fetching Modern

Mengelola penanganan race condition secara manual memang memberikan kita kontrol penuh atas setiap baris kode. Namun seiring berkembangnya skala aplikasi yang kita bangun, menulis logika pembatalan dan verifikasi secara manual di setiap komponen bisa jadi cukup melelahkan.

Untungnya ekosistem web development saat ini sudah memiliki library data fetching yang sangat canggih seperti TanStack Query atau sering kita kenal dengan sebutan React Query, serta library populer lainnya seperti SWR.

Library modern ini sudah menyertakan fitur penanganan race condition secara otomatis di belakang layar. Ketika sebuah query key berubah, library ini akan otomatis membatalkan request sebelumnya yang belum selesai atau langsung mengabaikan respon dari request yang sudah usang.

Selain menangani race condition, library tersebut juga memberikan fitur bonus yang sangat bermanfaat seperti pemeliharaan cache otomatis, penyegaran data di latar belakang, retrying saat gagal, serta manajemen indikator loading yang sangat mudah digunakan. Menggunakan library data fetching modern adalah pilihan bijak jika kita ingin fokus membangun fitur tanpa pusing memikirkan masalah asynchronous yang rumit.

Cara Menguji Bug Race Condition Di Browser Kita

Menemukan bug race condition saat tahap pengembangan lokal sering kali sulit karena jaringan komputer kita sangat cepat. Semua request terasa instan sehingga bug ini tidak pernah kelihatan.

Untuk mensimulasikan kejadian race condition secara nyata, kita bisa memanfaatkan fitur bawaan di browser developer tools. Buka tab Network pada developer tools browser kesayangan kita, lalu ubah pengaturan throttling jaringan dari No Throttling menjadi Slow 3G atau Fast 3G.

Dengan menurunkan kecepatan jaringan, setiap request fetch akan membutuhkan waktu beberapa detik untuk selesai. Di saat inilah kita bisa mencoba melakukan pengujian manual. Ketik sebuah kata kunci di pencarian, lalu langsung ubah dengan cepat ke kata kunci lain. Perhatikan apakah data yang muncul di layar sudah sesuai dengan input terakhir atau malah menampilkan data usang dari request pertama.

Pengujian ini sangat penting dilakukan untuk memastikan semua jurus pencegahan race condition yang sudah kita pasang benar benar bekerja dengan sempurna di berbagai kondisi jaringan pengguna.

Langkah Penting Menjaga Pengalaman Pengguna Tetap Smooth

Mencegah bug race condition dari sisi logika data adalah satu hal, tetapi memberikan indikasi visual yang jelas kepada pengguna adalah hal lain yang tidak kalah penting.

Selalu pastikan kita menampilkan indikator loading atau skeleton screen yang tepat saat proses fetching data sedang berlangsung. Indikator visual ini memberikan kepastian kepada pengguna bahwa aplikasi sedang bekerja memproses permintaan mereka.

Selain itu saat request dibatalkan menggunakan AbortController, browser akan melempar error dengan nama AbortError. Kita harus menangkap error ini di dalam blok catch dan tidak perlu memperlakukannya sebagai error berbahaya. Cukup abaikan AbortError tersebut agar tidak memunculkan notifikasi ganjil atau pesan kesalahan di layar pengguna.

Kesimpulan Dan Langkah Selanjutnya Buat Kita

Bug race condition saat fetch data memang sering menjadi masalah tersembunyi yang bisa merusak kenyamanan pengguna. Namun setelah kita memahami akar masalahnya, ternyata solusi buat mengatasinya sangat masuk akal dan relatif mudah diterapkan.

Kita bisa memilih menggunakan AbortController bawaan browser buat cara paling fleksibel, menerapkan teknik debounce buat mengurangi beban request, memakai verifikasi id request buat opsi alternatif, atau menyerahkan semuanya ke library modern seperti TanStack Query demi produktivitas tinggi.

Sekarang saatnya kita memeriksa kembali kode aplikasi yang pernah kita buat. Mari kita pastikan fitur pencarian, filter, dan fetching data di project kita sudah terbebas dari ancaman bug race condition agar pengalaman pengguna tetap berjalan lancar dan asik setiap saat.