Promise, fetch, async/await, hata yönetimi ve gerçek API pazarı.
Modern web uygulamaları sayfa yenilemeden sunucuyla veri alışverişi yapar. Bunu sağlayan teknoloji AJAX'tır. Günümüzde bunun için Fetch API kullanılır.
Asenkron işlemleri temsil eden nesnedir. Üç durumu vardır: pending (bekliyor), fulfilled (başarılı), rejected (başarısız). .then() başarı durumunu, .catch() hata durumunu yakalar.
Promise zinciri (.then().then().catch()) okunması güç olabilir. async/await aynı asenkron kodu senkron gibi yazmanızı sağlar. await yalnızca async fonksiyon içinde kullanılabilir.
Birden fazla isteği sırayla beklemek yerine Promise.all() ile hepsini aynı anda başlatıp hepsi bitince devam edebilirsiniz. Bu, birden fazla bağımsız veri çekme işlemini dramatik şekilde hızlandırır.
fetch() ağ hatasında reddeder (reject) ancak 404 veya 500 gibi HTTP hata kodlarında reddetmez! Bu yüzden response.ok veya response.status kontrolü zorunludur.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<style>
body { font-family: sans-serif; padding: 20px; max-width: 700px; }
button { padding: 10px 20px; background: #6366f1; color: white; border: none; border-radius: 8px; cursor: pointer; margin: 4px; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.kart { border: 1px solid #e2e8f0; border-radius: 12px; padding: 16px; margin: 10px 0; }
.hata { background: #fef2f2; border-color: #fca5a5; color: #dc2626; }
.yukleniyor { color: #64748b; }
#grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
</style>
</head>
<body>
<h2>Fetch API — Gerçek API Verisi</h2>
<div>
<button onclick="kullanicilariCek()">👥 Kullanıcıları Çek</button>
<button onclick="postCek(1)">📄 Post #1 Çek</button>
<button onclick="parallelCek()">⚡ Paralel Çek</button>
</div>
<div id="sonuc"></div>
<script>
const sonucDiv = document.getElementById('sonuc');
// ── Temel Fetch ──
async function kullanicilariCek() {
sonucDiv.innerHTML = '<p class="yukleniyor">⏳ Yükleniyor...</p>';
try {
const yanit = await fetch('https://jsonplaceholder.typicode.com/users?_limit=6');
if (!yanit.ok) {
throw new Error(`HTTP hatası: ${yanit.status} ${yanit.statusText}`);
}
const kullanicilar = await yanit.json();
const html = kullanicilar.map(k => `
<div class="kart">
<strong>${k.name}</strong><br>
<small>📧 ${k.email}</small><br>
<small>🌐 ${k.website}</small><br>
<small>🏢 ${k.company.name}</small>
</div>
`).join('');
sonucDiv.innerHTML = `<div id="grid">${html}</div>`;
} catch (hata) {
sonucDiv.innerHTML = `<div class="kart hata">❌ Hata: ${hata.message}</div>`;
}
}
// ── POST isteği ──
async function postGonder() {
const veri = {
title: 'Yeni Görev',
body: 'Görev açıklaması buraya gelir',
userId: 1,
};
try {
const yanit = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(veri),
});
const sonuc = await yanit.json();
console.log('Oluşturulan ID:', sonuc.id);
return sonuc;
} catch (hata) {
console.error('POST hatası:', hata);
}
}
async function postCek(id) {
sonucDiv.innerHTML = '<p class="yukleniyor">⏳ Yükleniyor...</p>';
try {
// Paralel olmayan — sırayla bekle
const postYanit = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
const yorumlarYanit = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}/comments?_limit=3`);
const post = await postYanit.json();
const yorumlar = await yorumlarYanit.json();
sonucDiv.innerHTML = `
<div class="kart">
<h3>${post.title}</h3>
<p>${post.body}</p>
<hr>
<h4>Yorumlar (${yorumlar.length})</h4>
${yorumlar.map(y => `<p>💬 <strong>${y.name}</strong>: ${y.body.slice(0,80)}...</p>`).join('')}
</div>
`;
} catch (hata) {
sonucDiv.innerHTML = `<div class="kart hata">❌ ${hata.message}</div>`;
}
}
// ── Promise.all ile Paralel İstek ──
async function parallelCek() {
sonucDiv.innerHTML = '<p class="yukleniyor">⏳ Paralel yükleniyor...</p>';
const baslangic = Date.now();
try {
// Hepsi aynı anda başlar, hepsi bitince devam eder
const [kullanicilar, postlar, albumler] = await Promise.all([
fetch('https://jsonplaceholder.typicode.com/users?_limit=3').then(r => r.json()),
fetch('https://jsonplaceholder.typicode.com/posts?_limit=3').then(r => r.json()),
fetch('https://jsonplaceholder.typicode.com/albums?_limit=3').then(r => r.json()),
]);
const sure = Date.now() - baslangic;
sonucDiv.innerHTML = `
<div class="kart">
<strong>3 istek ${sure}ms'de tamamlandı</strong>
<p>👥 ${kullanicilar.length} kullanıcı, 📄 ${postlar.length} post, 🖼 ${albumler.length} albüm</p>
<p>Kullanıcılar: ${kullanicilar.map(k => k.name).join(', ')}</p>
</div>
`;
} catch (hata) {
sonucDiv.innerHTML = `<div class="kart hata">❌ ${hata.message}</div>`;
}
}
// ── Timeout ile Fetch ──
async function zamanAsimiFetch(url, zamanAsimi = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), zamanAsimi);
try {
const yanit = await fetch(url, { signal: controller.signal });
clearTimeout(id);
return await yanit.json();
} catch (hata) {
if (hata.name === 'AbortError') {
throw new Error('İstek zaman aşımına uğradı!');
}
throw hata;
}
}
</script>
</body>
</html>