Subbab 5 / 9

JavaScript Lanjutan: DOM Dinamis, Asynchronous JavaScript, dan Fetch API

DOM Dinamis

Selama ini kita biasanya ngubah elemen yang udah ada di file HTML (misal ganti warna atau ganti teks). Lewat DOM Dinamis, JavaScript bisa bikin elemen HTML baru dari nol secara otomatis lewat kode.

Kenapa nggak ditulis langsung aja di file HTML?

  • Di file HTML biasa, tampilannya kaku dan statis.
  • Lewat JavaScript, kita bisa bikin elemen baru sesuai aksi user (misal user klik tombol tambah) atau mencetak puluhan data dari database tanpa ngetik tag HTML satu per satu secara manual.

Proses bikin elemen baru di JavaScript kurang lebih selalu ngikutin 4 langkah:

javascript
1
2
3
4
5
6
7
8
9
10
11
12
// 1. Siapkan Wadah Tujuan
const container = document.querySelector("#container");

// 2. Bikin Elemen Baru
const card = document.createElement("div");

// 3. Hias Elemen
card.textContent = "Data Mahasiswa";
card.classList.add("card");

// 4. Tempel ke Halaman Web
container.appendChild(card);

Hasil akhirnya di browser sama persis seperti kita ngetik manual di file HTML:

html
1
2
3
<div id="container">
    <div class="card">Data Mahasiswa</div>
</div>

Praktik Langsung: Fitur Tambah Skill

Biar kelihatan fungsinya di aplikasi nyata, kita gabungin 4 langkah tadi dengan event tombol dan input teks dari user.

html
1
2
3
4
5
6
<h2>Skill Saya</h2>

<input type="text" id="skillInput" placeholder="Masukkan skill">
<button id="addSkill">Tambah</button>

<ul id="skillList"></ul>
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const skillInput = document.querySelector("#skillInput");
const addSkill = document.querySelector("#addSkill");
const skillList = document.querySelector("#skillList");

addSkill.addEventListener("click", () => {
    const skill = skillInput.value;

    // Jangan proses kalau input masih kosong
    if (skill === "") {
        return;
    }

    // 1. Buat tag <li> baru
    const li = document.createElement("li");

    // 2. Isi teksnya dengan apa yang diketik user
    li.textContent = skill;

    // 3. Masukkan ke dalam <ul>
    skillList.appendChild(li);

    // 4. Kosongkan kembali form input
    skillInput.value = "";
});

Synchronous JavaScript

Secara bawaan, JavaScript ngerjain tugasnya secara Synchronous (berurutan dari atas ke bawah). Baris berikutnya harus nunggu baris sebelumnya kelar.

javascript
1
2
3
4
5
6
7
console.log("Mulai");

for (let i = 1; i <= 3; i++) {
    console.log("Proses", i);
}

console.log("Selesai");
plaintext
1
2
3
4
5
Mulai
Proses 1
Proses 2
Proses 3
Selesai

Masalahnya:

Gimana kalau salah satu baris kode butuh waktu lama? Misalnya minta data ke server luar negeri lewat internet lemot atau data yang ingin diambil jumlahnya ribuan bahkan jutaan.

Asynchronous

Yap betul, Asynchronous adalah jawaban dari pertanyaan sebelumnya. Asynchronous ngebiarin proses yang butuh waktu lama berjalan di latar belakang. Kode baris berikutnya tetap bisa langsung jalan tanpa harus nungguin proses lambat itu beres.

javascript
1
2
3
4
5
6
7
8
console.log("1. Mulai");

// Jalan 2 detik kemudian
setTimeout(() => {
    console.log("2. Proses selesai!");
}, 2000);

console.log("3. Selesai");
plaintext
1
2
3
1. Mulai
3. Selesai
2. Proses berat selesai!

Tulisan nomor 3 muncul duluan karena JavaScript nggak mau buang waktu nungguin setTimeout beres. Hal yang sama berlaku waktu kita ngambil data dari server.

Promise

Operasi asynchronous biasanya dibungkus dalam bentuk Promise. Bayangkan kamu pesan makanan di kasir fast food: kamu dikasih struk pesanan (janji). Makananmu belum ada sekarang, tapi bakal datang nanti.

3 Status Promise:

  • Pending: Masih nunggu proses kelar.
  • Fulfilled: Janji ditepati (data berhasil didapat) $\rightarrow$ ditangani lewat .then().
  • Rejected: Janji gagal (misal server mati atau kuota habis) $\rightarrow$ ditangani lewat .catch().
javascript
1
2
3
4
5
6
7
prosesAmbilData()
    .then(data => {
        console.log("Berhasil dapat data:", data);
    })
    .catch(error => {
        console.log("Ups, terjadi eror:", error);
    });

API & Format JSON

API (Application Programming Interface) adalah jembatan komunikasi antar aplikasi. Frontend web kita minta data ke backend via URL yang disebut endpoint.

Misal kita panggil URL:

[https://jsonplaceholder.typicode.com/users]

Server bakal ngirim balik data dalam format JSON (JavaScript Object Notation):

json
1
2
3
4
5
6
7
8
Bentuknya mirip banget sama Array dan Object JavaScript biasa, jadi gampang banget diolah.
[
    {
        "name": "Leanne Graham",
        "email": "[email protected]",
        "address": { "city": "Gwenborough" }
    }
]

Fetch API

Browser punya fitur bawaan bernama fetch() untuk ngambil data dari internet tanpa perlu reload halaman.

javascript
1
2
3
4
5
6
7
8
fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json()) // Ubah response mentah jadi format JSON
    .then(data => {
        console.log("Data diterima:", data);
    })
    .catch(error => {
        console.log("Koneksi gagal:", error);
    });

Alur Kerjanya

fetch(url) → Kirim Request → Response → response.json() → Data Siap Pakai

Fetch + DOM

Sekarang gabungin Fetch API sama manipulasi DOM. Data ribuan user dari server bisa kita cetak ke halaman web cuma pakai looping forEach().

html
1
2
<h1>Daftar Pengguna</h1>
<div id="container"></div>
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const container = document.querySelector("#container");

fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => response.json())
    .then(users => {
        // Cetak card untuk setiap user yang didapat dari server
        users.forEach(user => {
            container.innerHTML += `
                <div class="card">
                    <h2>${user.name}</h2>
                    <p>${user.email}</p>
                    <p>${user.address.city}</p>
                </div>
            `;
        });
    });

Loading & Error Handling

Internet nggak selalu lancar. Kadang server lemot atau kuota user habis. Karena itu, UI wajib ngasih tahu statusnya ke user biar nggak bingung ngeliat layar kosong melompong.

html
1
2
3
<h1>Daftar Pengguna</h1>
<p id="statusMsg">Memuat data...</p>
<div id="container"></div>
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const container = document.querySelector("#container");
const statusMsg = document.querySelector("#statusMsg");

fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => {
        if (!response.ok) {
            throw new Error("Gagal mengambil data dari server");
        }
        return response.json();
    })
    .then(users => {
        // Hapus teks loading setelah data sukses masuk
        statusMsg.textContent = "";

        users.forEach(user => {
            container.innerHTML += `
                <div class="card">
                    <h2>${user.name}</h2>
                    <p>${user.email}</p>
                    <p>${user.address.city}</p>
                </div>
            `;
        });
    })
    .catch(error => {
        // Tampilkan pesan eror jika ada masalah koneksi
        statusMsg.textContent = `${error.message}`;
        statusMsg.style.color = "red";
    });

Modern Alternative: async / await

Penulisan .then() berantai kadang bikin kode kelihatan berantakan kalau makin panjang. Di JavaScript modern, ada trik penulisan bernama async/await biar kode asynchronous terbaca rapi mirip kode biasa.

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
async function getUsers() {
    try {
        statusMsg.textContent = "Memuat data...";
        
        // await bertugas menghentikan baris berikutnya sampai fetch selesai
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        
        if (!response.ok) throw new Error("Gagal memuat data");

        const users = await response.json();

        statusMsg.textContent = "";
        users.forEach(user => {
            container.innerHTML += `
                <div class="card">
                    <h2>${user.name}</h2>
                    <p>${user.email}</p>
                    <p>${user.address.city}</p>
                </div>
            `;
        });
    } catch (error) {
        statusMsg.textContent = `Terjadi kesalahan: ${error.message}`;
    }
}

// Jalankan fungsinya
getUsers();
  • async: Menandai bahwa fungsi ini berjalan di latar belakang.
  • await: Menghentikan langkah di baris itu sementara sampai datanya beres diambil.
  • try...catch: Tempat buat nangkep eror kalau ada request yang gagal.

Pembeda

Gaya Tradisional (.then / .catch)

Gaya Modern (async/await)

Gaya Penulisan

Berantai (chaining callbacks)

Mirip kode sekuensial biasa (synchronous)

Error Handling

Menggunakan method .catch() di akhir rantai

Menggunakan blok standar try...catch

Keterbacaan

Masih mudah dipahami untuk proses sederhana, tetapi bisa lebih sulit dibaca jika rantainya panjang

Umumnya lebih mudah dibaca karena alurnya terlihat linier

Di Bawah Layar

Berjalan di atas Promise

Tetap menggunakan Promise; async/await adalah cara penulisan yang lebih nyaman di atas Promise

Contoh

fetch(url).then(...).catch(...)

const response = await fetch(url)

Jadi, biasanya pakai yang mana?

Untuk project JavaScript modern, async/await biasanya lebih sering digunakan, terutama ketika terdapat beberapa proses asynchronous karena alurnya lebih mudah dibaca dan dipelihara.

Namun, .then() dan .catch() bukan teknologi lama yang sudah tidak digunakan. Keduanya tetap penting untuk dipahami karena banyak kode JavaScript dan library yang menggunakan Promise chaining.