AJAX (Asynchronous JavaScript and XML) adalah teknik yang memungkinkan halaman web berkomunikasi dengan server di latar belakang — tanpa perlu reload halaman. Dulu dilakukan dengan XMLHttpRequest yang verbose, kini digantikan dengan Fetch API yang jauh lebih bersih dan modern.
Async JavaScript: Callback, Promise, Async/Await
Sebelum Fetch API, pahami dulu konsep asynchronous di JavaScript:
// Sinkron — berjalan berurutan, memblokir
console.log("Mulai");
const data = ambilDataDariServer(); // blok sampai selesai
console.log("Selesai");
// Asinkron — tidak memblokir, berjalan di background
console.log("Mulai");
ambilDataDariServer(function(data) { // callback — dijalankan setelah selesai
console.log("Data:", data);
});
console.log("Ini jalan duluan!");
// Output: "Mulai" → "Ini jalan duluan!" → "Data: ..."
Promise
// Promise: representasi nilai yang akan tersedia di masa depan
const janji = new Promise((resolve, reject) => {
const berhasil = true;
if (berhasil) resolve("Data berhasil!");
else reject(new Error("Gagal!"));
});
janji
.then(data => console.log(data)) // berhasil
.catch(err => console.error(err)) // gagal
.finally(() => console.log("Selesai")); // selalu dijalankan
Async/Await — Cara Paling Bersih
async function ambilData() {
try {
const response = await fetch("https://api.contoh.com/data");
const data = await response.json();
return data;
} catch (error) {
console.error("Gagal ambil data:", error);
}
}
Fetch API — Dasar
// GET request
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
// Dengan async/await (lebih bersih)
async function getPost(id) {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}
getPost(1).then(post => console.log(post));
Fetch dengan Berbagai Method HTTP
const BASE_URL = "https://jsonplaceholder.typicode.com";
// GET — ambil data
async function getUsers() {
const res = await fetch(`${BASE_URL}/users`);
return res.json();
}
// POST — kirim data baru
async function createPost(postData) {
const res = await fetch(`${BASE_URL}/posts`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify(postData)
});
return res.json();
}
// PUT — update penuh
async function updatePost(id, data) {
const res = await fetch(`${BASE_URL}/posts/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data)
});
return res.json();
}
// PATCH — update sebagian
async function patchPost(id, changes) {
const res = await fetch(`${BASE_URL}/posts/${id}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(changes)
});
return res.json();
}
// DELETE — hapus data
async function deletePost(id) {
const res = await fetch(`${BASE_URL}/posts/${id}`, {
method: "DELETE"
});
return res.ok;
}
Membuat Wrapper API yang Reusable
const api = {
baseURL: "https://api.kiki.my.id",
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const headers = {
"Content-Type": "application/json",
...options.headers
};
const token = localStorage.getItem("token");
if (token) headers["Authorization"] = `Bearer ${token}`;
const response = await fetch(url, { ...options, headers });
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}`);
}
if (response.status === 204) return null;
return response.json();
},
get(endpoint) { return this.request(endpoint); },
post(endpoint, data) { return this.request(endpoint, { method: "POST", body: JSON.stringify(data) }); },
put(endpoint, data) { return this.request(endpoint, { method: "PUT", body: JSON.stringify(data) }); },
patch(endpoint, data) { return this.request(endpoint, { method: "PATCH", body: JSON.stringify(data) }); },
delete(endpoint) { return this.request(endpoint, { method: "DELETE" }); }
};
// Penggunaan
const posts = await api.get("/posts");
const newPost = await api.post("/posts", { title: "Judul", body: "Isi..." });
Contoh Praktis: Tampilkan Data dari API
<div id="loading" style="display:none">Memuat data...</div>
<div id="error" style="display:none"></div>
<ul id="daftar-user"></ul>
async function tampilkanUsers() {
const loading = document.querySelector("#loading");
const errorEl = document.querySelector("#error");
const daftar = document.querySelector("#daftar-user");
loading.style.display = "block";
errorEl.style.display = "none";
try {
const users = await api.get("/users");
daftar.innerHTML = users.map(user => `
<li>
<strong>${user.nama}</strong> — ${user.email}
</li>
`).join("");
} catch (error) {
errorEl.textContent = `Error: ${error.message}`;
errorEl.style.display = "block";
} finally {
loading.style.display = "none";
}
}
document.addEventListener("DOMContentLoaded", tampilkanUsers);
Promise.all — Beberapa Request Paralel
// Jalankan beberapa fetch SECARA BERSAMAAN
async function loadDashboard() {
const [users, posts, stats] = await Promise.all([
api.get("/users"),
api.get("/posts"),
api.get("/stats")
]);
renderUsers(users);
renderPosts(posts);
renderStats(stats);
}
// Promise.allSettled — jalan semua, tidak peduli yang gagal
const results = await Promise.allSettled([
fetch("/api/a"),
fetch("/api/b"),
fetch("/api/c")
]);
results.forEach(result => {
if (result.status === "fulfilled") console.log(result.value);
else console.error(result.reason);
});
Kesimpulan
Fetch API dengan async/await adalah cara standar modern untuk berkomunikasi dengan server dari JavaScript. Dengan membuat wrapper API yang reusable, kode AJAX kamu menjadi bersih, konsisten, dan mudah di-maintain.
Di artikel berikutnya, kita masuk ke dunia jQuery — library JavaScript yang menyederhanakan manipulasi DOM dan AJAX.
Kiki/🎮🍉⌨️🍩💻