0%

🌐 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.

javascript

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!"]);
}
?>