🌐 Fetch API un AJAX
Fetch API ļauj nosūtīt HTTP pieprasījumus un saņemt datus no serveriem bez lapas atkārtotas ielādes. Kopā ar async/await kods ir skaidrs un lasāms.
fetch() pamati
ℹ️
HTTP statusa kodi
200-299 = veiksmīgi, 400 = sliktsprasījums, 401 = nav autorizācijas, 403 = aizliegts, 404 = nav atrasts, 500 = servera kļūda. Vienmēr pārbaudiet atbilde.ok!
Teksts
// fetch() atgriež Promise
fetch("https://jsonplaceholder.typicode.com/users/1")
.then(atbilde => {
console.log(atbilde.status); // 200
console.log(atbilde.ok); // true (ja 200-299)
return atbilde.json(); // Parsē JSON, atgriež Promise
})
.then(dati => {
console.log(dati.name); // "Leanne Graham"
})
.catch(kļūda => {
console.error("Kļūda:", kļūda);
});
// ======================================
// Labāks veids – async/await
// ======================================
async function iegūtLietotāju(id) {
try {
const atbilde = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
if (!atbilde.ok) {
throw new Error(`HTTP kļūda! Statuss: ${atbilde.status}`);
}
const lietotājs = await atbilde.json();
return lietotājs;
} catch (kļūda) {
console.error("Neizdevās iegūt lietotāju:", kļūda);
return null;
}
}
// Izsaukšana
const lietotājs = await iegūtLietotāju(1);
console.log(lietotājs?.name); // "Leanne Graham"
POST, PUT un DELETE pieprasījumi
Teksts
// ======================================
// POST – nosūtīt jaunus datus
// ======================================
async function izveidotIerakstu(dati) {
const atbilde = await fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(dati),
});
if (!atbilde.ok) throw new Error(`Kļūda: ${atbilde.status}`);
return await atbilde.json();
}
const jaunais = await izveidotIerakstu({
title: "Mans ieraksts",
body: "Saturs šeit",
userId: 1
});
console.log("Izveidots:", jaunais.id); // 101
// ======================================
// PUT – atjaunināt esošu
// ======================================
async function atjaunināt(id, dati) {
const atbilde = await fetch(`https://api.example.lv/ieraksti/${id}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(dati),
});
return await atbilde.json();
}
// ======================================
// DELETE – dzēst
// ======================================
async function dzēst(id) {
const atbilde = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`, {
method: "DELETE",
});
return atbilde.ok; // true ja veiksmīgi
}
const veiksmīgi = await dzēst(1);
console.log("Dzēsts:", veiksmīgi); // true
Ielādes rādіtājs un atcelšana
Teksts
// ======================================
// Ielādes rādītājs
// ======================================
async function ielādētArRādītāju(url, rādītāja_elements) {
rādītāja_elements.style.display = "block";
try {
const atbilde = await fetch(url);
const dati = await atbilde.json();
return dati;
} finally {
rādītāja_elements.style.display = "none"; // Vienmēr slēpj
}
}
// ======================================
// AbortController – pieprasījuma atcelšana
// ======================================
let kontrolieris = null;
async function meklēt(vaicājums) {
// Atcelt iepriekšējo meklēšanu
kontrolieris?.abort();
kontrolieris = new AbortController();
try {
const atbilde = await fetch(
`https://api.example.lv/meklēt?q=${encodeURIComponent(vaicājums)}`,
{ signal: kontrolieris.signal } // Piesaistīt kontrolieri
);
return await atbilde.json();
} catch (kļūda) {
if (kļūda.name === "AbortError") {
console.log("Pieprasījums atcelts");
return null;
}
throw kļūda;
}
}
// Laika limits (timeout)
async function fetchArLimitu(url, ms = 5000) {
const kontrolieris = new AbortController();
const taimeris = setTimeout(() => kontrolieris.abort(), ms);
try {
const atbilde = await fetch(url, { signal: kontrolieris.signal });
clearTimeout(taimeris);
return await atbilde.json();
} catch (kļūda) {
if (kļūda.name === "AbortError") throw new Error("Pieprasījums pārsniedza laika limitu");
throw kļūda;
}
}
Paralēlie pieprasījumi
Teksts
// ======================================
// Promise.all – visi vienlaicīgi
// ======================================
async function iegūtVairākus() {
// Visi sākas vienlaicīgi! Ātrāk nekā secīgi.
const [lietotāji, ieraksti, komentāri] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/users").then(r => r.json()),
fetch("https://jsonplaceholder.typicode.com/posts").then(r => r.json()),
fetch("https://jsonplaceholder.typicode.com/comments").then(r => r.json()),
]);
console.log(lietotāji.length); // 10
console.log(ieraksti.length); // 100
console.log(komentāri.length); // 500
}
// ======================================
// Promise.allSettled – kad daži var neizdevties
// ======================================
async function iegūtDrošiVairākus(urls) {
const rezultāti = await Promise.allSettled(
urls.map(url => fetch(url).then(r => r.json()))
);
return rezultāti.map((rez, i) => ({
url: urls[i],
veiksmīgs: rez.status === "fulfilled",
dati: rez.value ?? null,
kļūda: rez.reason?.message ?? null,
}));
}
// ======================================
// Promise.race – pirmais uzvar
// ======================================
const ātrs_serveris = await Promise.race([
fetch("https://api1.example.lv/dati"),
fetch("https://api2.example.lv/dati"),
fetch("https://api3.example.lv/dati"),
]); // Atgriež atbildi no ātrākā servera
Piemērs ar PHP aizkulisēm
Teksts
// ======================================
// Formas iesniegšana ar fetch (bez lapas pārlādes)
// ======================================
document.querySelector("#kontaktu-forma").addEventListener("submit", async e => {
e.preventDefault();
const poga = e.target.querySelector("button[type=submit]");
const ziņa = document.querySelector("#ziņa");
// Ielādes stāvoklis
poga.disabled = true;
poga.textContent = "Nosūta...";
const dati = new FormData(e.target); // Automātiski savāc formas datus
try {
const atbilde = await fetch("apstrāde.php", {
method: "POST",
body: dati, // FormData nekodē JSON, nosūta multipart/form-data
});
const rezultāts = await atbilde.json();
if (rezultāts.veiksmīgi) {
ziņa.className = "ziņa veiksmīga";
ziņa.textContent = "Ziņa nosūtīta!";
e.target.reset();
} else {
throw new Error(rezultāts.kļūda ?? "Nezināma kļūda");
}
} catch (kļūda) {
ziņa.className = "ziņa kļūda";
ziņa.textContent = "Kļūda: " + kļūda.message;
} finally {
poga.disabled = false;
poga.textContent = "Nosūtīt";
}
});
<?php
// apstrāde.php – PHP aizkulišu apstrāde
header("Content-Type: application/json");
// Fake response for example
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$vārds = trim($_POST["vārds"] ?? "");
$email = trim($_POST["email"] ?? "");
if (!$vārds || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
http_response_code(400);
echo json_encode(["veiksmīgi" => false, "kļūda" => "Derīgi dati trūkst"]);
exit;
}
// Apstrāde (saglabā DB, sūta epastuutml.)
echo json_encode(["veiksmīgi" => true, "ziņa" => "Paldies, $vārds!"]);
}
?>