Generatiivinen tiedustelu

Tietojen välimuisti SvelteKitissä

Treffi:

My Edellinen viesti oli laaja yleiskatsaus SvelteKitistä, jossa näimme kuinka loistava työkalu se on web-kehitykseen. Tämä viesti kertoo, mitä teimme siellä, ja sukeltaa jokaisen kehittäjän suosikkiaiheeseen: välimuistia. Muista siis lukea viimeinen viestini, jos et ole jo lukenut. Tämän viestin koodi on saatavilla GitHubissaSekä live demo.

Tämä viesti koskee tietojenkäsittelyä. Lisäämme alkeellisia hakutoimintoja, jotka muokkaavat sivun kyselymerkkijonoa (käyttämällä sisäänrakennettuja SvelteKit-ominaisuuksia) ja käynnistävät sivun latausohjelman uudelleen. Mutta sen sijaan, että teemme vain uudelleenkyselyjä (kuvitteellisesta) tietokannastamme, lisäämme välimuistiin, jotta aikaisempien hakujen uudelleenhaku (tai takaisin-painikkeen käyttäminen) näyttää aiemmin haetut tiedot nopeasti välimuistista. Tarkastellaan, kuinka voit hallita välimuistissa olevien tietojen voimassaoloaikaa, ja mikä tärkeintä, kuinka mitätöidä kaikki välimuistissa olevat arvot manuaalisesti. Huippuna kakun päällä tarkastelemme, kuinka voimme päivittää tiedot manuaalisesti nykyisellä näytöllä, asiakaspuolella, mutaation jälkeen, samalla kun välimuistia tyhjennetään.

Tämä on pidempi, vaikeampi postaus kuin useimmat tavalliset kirjoitukset, koska käsittelemme vaikeampia aiheita. Tämä viesti näyttää pohjimmiltaan, kuinka voit ottaa käyttöön suosittujen dataapuohjelmien, kuten esimerkiksi, yhteisiä ominaisuuksia reagoi-kysely; mutta sen sijaan, että otamme käyttöön ulkoisen kirjaston, käytämme vain verkkoalustaa ja SvelteKit-ominaisuuksia.

Valitettavasti verkkoalustan ominaisuudet ovat hieman alemmalla tasolla, joten teemme hieman enemmän työtä kuin olet tottunut. Kääntöpuolena on, että emme tarvitse ulkoisia kirjastoja, mikä auttaa pitämään nippukoot pieninä. Älä käytä lähestymistapoja, jotka aion näyttää sinulle, ellei sinulla ole siihen hyvää syytä. Välimuistissa on helppo erehtyä, ja kuten huomaat, sovelluskoodisi on monimutkainen. Toivottavasti tietovarasto on nopea ja käyttöliittymäsi on kunnossa, joten SvelteKit voi aina pyytää tarvitsemansa tiedot mille tahansa sivulle. Jos on, jätä se rauhaan. Nauti yksinkertaisuudesta. Mutta tämä viesti näyttää sinulle joitain temppuja, kun se lakkaa olemasta.

Reaktiokyselystä puheen ollen, se vapautettiin juuri Svelten puolesta! Joten jos huomaat nojautuvasi manuaalisiin välimuistitekniikoihin paljon, muista tarkistaa kyseinen projekti ja katso, voisiko se auttaa.

Asettaa

Ennen kuin aloitamme, tehdään muutama pieni muutos koodi, joka meillä oli aiemmin. Tämä antaa meille tekosyyn nähdä joitain muita SvelteKitin ominaisuuksia ja mikä tärkeintä, valmistaa meidät menestymään.

Siirretään ensin datalataus lataajasta sisään +page.server.js ja API-reitti. Luomme a +server.js tiedosto routes/api/todosja lisää sitten a GET toiminto. Tämä tarkoittaa, että voimme nyt hakea (käyttämällä oletusarvoista GET-verbiä) osoitteeseen /api/todos polku. Lisäämme saman tiedonlatauskoodin kuin ennenkin.

import { json } from "@sveltejs/kit";
import { getTodos } from "$lib/data/todoData"; export async function GET({ url, setHeaders, request }) { const search = url.searchParams.get("search") || ""; const todos = await getTodos(search); return json(todos);
}

Otetaan seuraavaksi käytössä oleva sivunlatausohjelma ja nimetään tiedosto uudelleen +page.server.js että +page.js (Tai .ts jos olet rakentanut projektisi käyttämään TypeScriptiä). Tämä muuttaa lataajamme "universaaliksi" lataajaksi palvelinlataimen sijaan. SvelteKit-dokumentit selitä ero, mutta yleinen latausohjelma toimii sekä palvelimella että asiakaskoneella. Yksi etu meille on, että fetch kutsu uuteen päätepisteeseemme toimii suoraan selaimestamme (alkulatauksen jälkeen) käyttämällä selaimen alkuperäistä fetch toiminto. Lisäämme hieman normaalin HTTP-välimuistin, mutta toistaiseksi soitamme vain päätepisteeseen.

export async function load({ fetch, url, setHeaders }) { const search = url.searchParams.get("search") || ""; const resp = await fetch(`/api/todos?search=${encodeURIComponent(search)}`); const todos = await resp.json(); return { todos, };
}

Lisätään nyt meille yksinkertainen lomake /list sivu:

<div class="search-form"> <form action="/fi/list"> <label>Search</label> <input autofocus name="search" /> </form>
</div>

Kyllä, lomakkeet voivat kohdistaa suoraan tavallisiin sivunlataajiimme. Nyt voimme lisätä hakusanan hakukenttään, paina enter, ja "haku"-termi liitetään URL-osoitteen kyselymerkkijonoon, joka käynnistää latausohjelman uudelleen ja hakee tehtäväkohteistamme.

hakulomake

Lisätään myös viivettä todoData.js tiedosto /lib/data. Näin on helppo nähdä, milloin tiedot ovat välimuistissa ja milloin ei, kun käsittelemme tätä viestiä.

export const wait = async amount => new Promise(res => setTimeout(res, amount ?? 500));

Muista, että tämän viestin koko koodi on kaikki GitHubissa, jos sinun on viitattava siihen.

Perusvälimuisti

Aloitetaan lisäämällä välimuistiin /api/todos päätepiste. Palaamme omaan +server.js tiedosto ja lisää ensimmäinen välimuistin ohjausotsikko.

setHeaders({ "cache-control": "max-age=60",
});

…joka jättää koko toiminnon näyttämään tältä:

export async function GET({ url, setHeaders, request }) { const search = url.searchParams.get("search") || ""; setHeaders({ "cache-control": "max-age=60", }); const todos = await getTodos(search); return json(todos);
}

Tarkastelemme manuaalista mitätöintiä pian, mutta tämä toiminto käskee vain tallentaa nämä API-kutsut 60 sekunnin ajaksi. Aseta tämä mihin haluatja käyttötapauksestasi riippuen stale-while-revalidate saattaa myös olla tutustumisen arvoinen.

Ja juuri näin, kyselymme tallentuvat välimuistiin.

Välimuisti DevToolsissa.

Huomautuksia Varmista, että sinä poista valinta valintaruutu, joka poistaa välimuistin käytön kehitystyökaluissa.

Muista, että jos ensimmäinen navigointisi sovelluksessa on luettelosivu, hakutulokset tallennetaan sisäisesti SvelteKitin välimuistiin, joten älä odota näkeväsi mitään DevToolsissa, kun palaat kyseiseen hakuun.

Mitä välimuistissa on ja missä

Aivan ensimmäinen, palvelimen suorittama sovelluksemme lataus (olettaen, että aloitamme /list sivu) noudetaan palvelimelta. SvelteKit sarjoittaa ja lähettää nämä tiedot asiakkaallemme. Mikä parasta, se tarkkailee Cache-Control ylätunniste vastauksessa ja osaa käyttää tätä välimuistissa olevaa dataa kyseiselle päätepistekutsulle välimuistiikkunassa (jonka asetimme 60 sekuntiin put-esimerkissä).

Alkulatauksen jälkeen, kun aloitat haun sivulla, sinun pitäisi nähdä verkkopyynnöt selaimeltasi /api/todos lista. Kun etsit asioita, joita olet jo etsinyt (viimeisten 60 sekunnin aikana), vastausten pitäisi latautua välittömästi, koska ne on tallennettu välimuistiin.

Erityisen siistiä tässä lähestymistavassa on se, että koska kyseessä on välimuistin tallentaminen selaimen alkuperäisen välimuistin kautta, nämä kutsut voivat (riippuen siitä, kuinka hallitset välimuistin katkaisua, jota tarkastelemme) jatkaa välimuistia, vaikka lataat sivun uudelleen (toisin kuin alkuperäinen palvelinpuolen kuormitus, joka kutsuu päätepistettä aina tuoreena, vaikka se tekisi sen viimeisen 60 sekunnin aikana).

Ilmeisesti tiedot voivat muuttua milloin tahansa, joten tarvitsemme tavan tyhjentää tämä välimuisti manuaalisesti, mitä tarkastelemme seuraavaksi.

Välimuistin mitätöinti

Tällä hetkellä tiedot säilytetään välimuistissa 60 sekunnin ajan. Ei väliä mitä tahansa, minuutin kuluttua tuoretta dataa vedetään tietovarastostamme. Haluat ehkä lyhyemmän tai pidemmän ajanjakson, mutta mitä tapahtuu, jos muutat tietoja ja haluat tyhjentää välimuistin välittömästi, jotta seuraava kyselysi on ajan tasalla? Ratkaisemme tämän lisäämällä kyselyn estoarvon URL-osoitteeseen, jonka lähetämme uuteen osoitteeseen /todos päätepiste.

Tallennetaan tämä välimuistin eston arvo evästeeseen. Tämä arvo voidaan asettaa palvelimella, mutta silti lukea asiakkaalla. Katsotaanpa esimerkkikoodia.

Voimme luoda a +layout.server.js tiedostomme aivan ytimessä routes kansio. Tämä toimii sovelluksen käynnistyksen yhteydessä, ja se on täydellinen paikka määrittää alkuevästearvo.

export function load({ cookies, isDataRequest }) { const initialRequest = !isDataRequest; const cacheValue = initialRequest ? +new Date() : cookies.get("todos-cache"); if (initialRequest) { cookies.set("todos-cache", cacheValue, { path: "/", httpOnly: false }); } return { todosCacheBust: cacheValue, };
}

Olet ehkä huomannut isDataRequest arvo. Muista, että asettelut suoritetaan uudelleen milloin tahansa asiakaskoodikutsujen yhteydessä invalidate(), tai milloin tahansa suoritamme palvelintoiminnon (olettaen, että emme poista oletustoimintoa käytöstä). isDataRequest ilmaisee nämä uudelleenkäynnit, joten asetamme evästeen vain, jos se on false; muussa tapauksessa lähetämme mukana sen, mitä on jo olemassa.

- httpOnly: false lippu on myös tärkeä. Näin asiakaskoodimme voi lukea nämä evästearvot sisään document.cookie. Tämä olisi yleensä turvallisuusongelma, mutta meidän tapauksessamme nämä ovat merkityksettömiä numeroita, joiden avulla voimme tallentaa välimuistiin tai välimuistiin.

Välimuistin arvojen lukeminen

Yleiskuormaajamme on meidän /todos päätepiste. Tämä toimii palvelimella tai asiakkaalla, ja meidän on luettava juuri asettamamme välimuistiarvo riippumatta siitä, missä olemme. Se on suhteellisen helppoa, jos olemme palvelimella: voimme soittaa await parent() saadaksesi tiedot ylätason asetteluista. Mutta asiakkaalla meidän on käytettävä bruttokoodia jäsentämiseen document.cookie:

export function getCookieLookup() { if (typeof document !== "object") { return {}; } return document.cookie.split("; ").reduce((lookup, v) => { const parts = v.split("="); lookup[parts[0]] = parts[1]; return lookup; }, {});
} const getCurrentCookieValue = name => { const cookies = getCookieLookup(); return cookies[name] ?? "";
};

Onneksi tarvitsemme sitä vain kerran.

Välimuistin arvon lähettäminen

Mutta nyt meidän täytyy lähettää tämä arvo meille /todos päätepiste.

import { getCurrentCookieValue } from "$lib/util/cookieUtils"; export async function load({ fetch, parent, url, setHeaders }) { const parentData = await parent(); const cacheBust = getCurrentCookieValue("todos-cache") || parentData.todosCacheBust; const search = url.searchParams.get("search") || ""; const resp = await fetch(`/api/todos?search=${encodeURIComponent(search)}&cache=${cacheBust}`); const todos = await resp.json(); return { todos, };
}

getCurrentCookieValue('todos-cache') tarkistaa, olemmeko asiakkaalla (tarkistamalla asiakirjan tyypin), eikä palauta mitään, jos olemme, jolloin tiedämme, että olemme palvelimella. Sitten se käyttää asettelumme arvoa.

Välimuistin murtaminen

Mutta miten Päivitämmekö välimuistin katkaisun arvon tarvittaessa? Koska se on tallennettu evästeeseen, voimme kutsua sitä seuraavasti mistä tahansa palvelintoiminnosta:

cookies.set("todos-cache", cacheValue, { path: "/", httpOnly: false });

Toimeenpano

Kaikki on alamäkeä täältä; olemme tehneet kovan työn. Olemme käsitelleet tarvitsemamme erilaiset verkkoalustan primitiivit sekä niiden sijainnin. Pidetään nyt hauskaa ja kirjoitetaan sovelluskoodi yhdistääksesi kaikki.

Hetken kuluttua selviävistä syistä aloitetaan lisäämällä muokkaustoiminto /list sivu. Lisäämme tämän toisen taulukkorivin jokaiselle tehtävälle:

import { enhance } from "$app/forms";
<tr> <td colspan="4"> <form use:enhance method="post" action="?/editTodo"> <input name="id" value="{t.id}" type="hidden" /> <input name="title" value="{t.title}" /> <button>Save</button> </form> </td>
</tr>

Ja tietysti meidän on lisättävä lomaketoiminto /list sivu. Toimet voivat vain mennä sisään .server sivuja, joten lisäämme a +page.server.js meidän /list kansio. (Kyllä A +page.server.js tiedosto voi olla rinnakkain a:n vieressä +page.js tiedosto.)

import { getTodo, updateTodo, wait } from "$lib/data/todoData"; export const actions = { async editTodo({ request, cookies }) { const formData = await request.formData(); const id = formData.get("id"); const newTitle = formData.get("title"); await wait(250); updateTodo(id, newTitle); cookies.set("todos-cache", +new Date(), { path: "/", httpOnly: false }); },
};

Tartumme lomaketietoihin, pakotamme viiveen, päivitämme tehtävämme ja, mikä tärkeintä, tyhjennämme välimuistin häiriöevästeen.

Kokeillaan tätä. Lataa sivusi uudelleen ja muokkaa sitten jotakin tehtäväkohdetta. Sinun pitäisi nähdä taulukon arvon päivitys hetken kuluttua. Jos katsot DevTooldin Verkko-välilehteä, näet haun osoitteeseen /todos päätepiste, joka palauttaa uudet tietosi. Yksinkertainen ja oletusarvoisesti toimiva.

Tietojen tallentaminen

Välittömät päivitykset

Entä jos haluamme välttää sen haun, joka tapahtuu sen jälkeen, kun olemme päivittäneet tehtävämme, ja sen sijaan päivittää muokatun kohteen suoraan näytöllä?

Tämä ei ole vain suorituskysymys. Jos haet sanalla "post" ja poistat sitten sanan "post" mistä tahansa luettelon tehtäväkohteesta, ne katoavat luettelosta muokkauksen jälkeen, koska ne eivät enää ole kyseisen sivun hakutuloksissa. Voisit tehdä käyttökokemuksesta paremman tyylikkäällä animaatiolla jännittävää tekemistä varten, mutta oletetaan, että halusimme emme Suorita sivun lataustoiminto uudelleen, mutta tyhjennä välimuisti ja päivitä muokattu tehtävä, jotta käyttäjä näkee muokkauksen. SvelteKit tekee sen mahdolliseksi – katsotaanpa miten!

Tehdään ensin pieni muutos kuormaajaamme. Sen sijaan, että palauttaisimme tehtävämme, palautetaan a kirjoitettava kauppa sisältää tehtävämme.

return { todos: writable(todos),
};

Ennen olimme käsissämme tehtäviämme sivulla data prop, jota emme omista emmekä voi päivittää. Mutta Svelte antaa meidän palauttaa tietomme omassa myymälässään (olettaen, että käytämme yleiskuormaajaa, jota olemme). Meidän täytyy vain tehdä vielä yksi säätö /list sivu.

Tämän sijaan:

{#each todos as t}

…meidän on tehtävä tämä siitä lähtien todos on itse nyt kauppa.:

{#each $todos as t}

Nyt tietomme latautuvat kuten ennenkin. Mutta siitä lähtien todos on kirjoitettava kauppa, voimme päivittää sen.

Ensin tarjotaan meille toiminto use:enhance määrite:

<form use:enhance={executeSave} on:submit={runInvalidate} method="post" action="?/editTodo"
>

Tämä suoritetaan ennen lähetystä. Kirjoitetaan seuraavaksi:

function executeSave({ data }) { const id = data.get("id"); const title = data.get("title"); return async () => { todos.update(list => list.map(todo => { if (todo.id == id) { return Object.assign({}, todo, { title }); } else { return todo; } }) ); };
}

Tämä toiminto tarjoaa a data lomaketietojemme kanssa. Me palata asynkronointitoiminto, joka suoritetaan jälkeen muokkaksemme on tehty. Asiakirjat selittää kaiken tämän, mutta tekemällä näin sammutimme SvelteKitin oletuslomakkeenkäsittelyn, joka olisi ajanut lataajamme uudelleen. Tämä on juuri sitä mitä haluamme! (Voimme helposti palauttaa tämän oletuskäyttäytymisen, kuten asiakirjat selittävät.)

Nyt soitetaan update meidän todos joukko, koska se on kauppa. Ja siinä se. Kun olet muokannut tehtävää, muutokset tulevat näkyviin välittömästi ja välimuistimme tyhjennetään (kuten ennenkin, koska asetimme uuden evästearvon editTodo muototoiminto). Joten jos teemme haun ja siirrymme takaisin tälle sivulle, saamme lataajaltamme tuoreita tietoja, jotka sulkevat oikein pois päivitetyt tehtävät, jotka on päivitetty.

Koodi välittömiä päivityksiä varten on saatavilla GitHubista.

Kaivaa syvemmälle

Voimme asettaa evästeitä mihin tahansa palvelimen lataustoimintoon (tai palvelintoimintoon), ei vain juuriasetteluun. Joten jos joitain tietoja käytetään vain yhden asettelun tai jopa yhden sivun alla, voit asettaa evästearvon sinne. Lisäksi, jos olet emme tein tempun, jonka näytin juuri päivittäväni näytöllä näkyvät tiedot manuaalisesti, ja haluan sen sijaan lataajasi ajavan uudelleen mutaation jälkeen, niin voit aina asettaa uuden evästearvon suoraan kyseiseen lataustoimintoon ilman tarkistusta. isDataRequest. Se asetetaan aluksi, ja sitten aina, kun suoritat palvelintoiminnon, sivuasettelu mitätöi automaattisesti ja kutsuu lataajasi uudelleen. Se asettaa välimuistin häiriömerkkijonon uudelleen ennen kuin yleislataajasi kutsutaan.

Uudelleenlatausfunktion kirjoittaminen

Päätetään rakentamalla viimeinen ominaisuus: latauspainike. Annetaan käyttäjille painike, joka tyhjentää välimuistin ja lataa sitten nykyisen kyselyn uudelleen.

Lisäämme lian yksinkertaisen lomakkeen toiminnon:

async reloadTodos({ cookies }) { cookies.set('todos-cache', +new Date(), { path: '/', httpOnly: false });
},

Oikeassa projektissa et luultavasti kopioi/liitä samaa koodia asettaaksesi saman evästeen samalla tavalla useisiin paikkoihin, mutta tätä viestiä varten optimoimme yksinkertaisuuden ja luettavuuden.

Luodaan nyt lomake siihen lähetettäväksi:

<form method="POST" action="?/reloadTodos" use:enhance> <button>Reload todos</button>
</form>

Se toimii!

Käyttöliittymä uudelleenlatauksen jälkeen.

Voisimme kutsua tätä valmiiksi ja jatkaa eteenpäin, mutta parannetaan tätä ratkaisua hieman. Tarkemmin sanottuna annetaan palautetta sivulla kertoaksemme käyttäjälle, että uudelleenlataus tapahtuu. Myös oletusarvoisesti SvelteKit-toiminnot mitätöivät kaikki. Jokainen nykyisen sivun hierarkian asettelu, sivu jne. latautuu uudelleen. Joitakin tietoja, jotka on ladattu kerran juuriasettelussa, saattaa olla, joita meidän ei tarvitse mitätöidä tai ladata uudelleen.

Keskitytään siis asioihin hieman ja ladataan tehtävämme uudelleen vain, kun kutsumme tätä toimintoa.

Välitetään ensin parannettava toiminto:

<form method="POST" action="?/reloadTodos" use:enhance={reloadTodos}>
import { enhance } from "$app/forms";
import { invalidate } from "$app/navigation"; let reloading = false;
const reloadTodos = () => { reloading = true; return async () => { invalidate("reload:todos").then(() => { reloading = false; }); };
};

Asetamme uuden reloading muuttuja true klo Alkaa tästä toiminnasta. Ja sitten, ohittaaksemme oletuskäyttäytymisen kaiken mitätöimiseksi, palautamme an async toiminto. Tämä toiminto käynnistyy, kun palvelintoimintomme on valmis (joka asettaa vain uuden evästeen).

Ilman tätä async funktio palautettiin, SvelteKit mitätöisi kaiken. Koska tarjoamme tämän toiminnon, se ei mitätöi mitään, joten on meidän tehtävämme kertoa sille, mitä se ladataan uudelleen. Teemme tämän kanssa invalidate toiminto. Kutsumme sitä arvolla reload:todos. Tämä funktio palauttaa lupauksen, joka ratkeaa, kun mitätöinti on valmis, jolloin asetamme sen reloading takaisin false.

Lopuksi meidän on synkronoitava latausohjelmamme tämän uuden kanssa reload:todos mitätöintiarvo. Teemme sen kuormaimessamme depends toiminto:

export async function load({ fetch, url, setHeaders, depends }) { depends('reload:todos'); // rest is the same

Ja se on. depends ja invalidate ovat uskomattoman hyödyllisiä toimintoja. Se on siistiä invalidate ei vain ota mielivaltaisia ​​arvoja, joita tarjoamme, kuten teimme. Voimme myös tarjota URL-osoitteen, jota SvelteKit seuraa, ja mitätöidä kaikki kyseisestä URL-osoitteesta riippuvat lataajat. Tätä varten, jos mietit, voisimmeko jättää puhelun väliin depends ja mitätöidä meidän /api/todos päätepiste kokonaisuudessaan, voit, mutta sinun on annettava tarkka URL-osoite, mukaan lukien search termi (ja välimuistin arvomme). Joten voit joko koota URL-osoitteen nykyiselle haulle tai vastata polun nimeen seuraavasti:

invalidate(url => url.pathname == "/api/todos");

Henkilökohtaisesti löydän ratkaisun, joka käyttää depends selkeämpi ja yksinkertaisempi. Mutta katso asiakirjat Tietysti saat lisätietoa ja päätä itse.

Jos haluat nähdä uudelleenlatauspainikkeen toiminnassa, sen koodi löytyy tämä repon haara.

Erimielisyydet

Tämä oli pitkä postaus, mutta toivottavasti ei ylivoimainen. Otimme käyttöön erilaisia ​​tapoja tallentaa tietoja välimuistiin SvelteKitin käytön aikana. Suurin osa tästä oli vain verkkoalustan primitiivien käyttämistä oikean välimuistin ja evästearvojen lisäämiseen, joiden tunteminen palvelee sinua verkkokehityksessä yleensä, SvelteKitin lisäksi.

Lisäksi tämä on jotain sinun ehdottomasti ei tarvitse koko aikaa. Luultavasti sinun pitäisi tavoittaa tällaisia ​​edistyneitä ominaisuuksia vain, kun todella tarvitsevat niitä. Jos tietovarastosi palvelee tietoja nopeasti ja tehokkaasti, etkä ole tekemisissä minkäänlaisten skaalausongelmien kanssa, ei ole mitään järkeä turvottaa sovelluskoodiasi turhaan monimutkaisuuteen ja tehdä asioita, joista puhuimme täällä.

Kuten aina, kirjoita selkeä, puhdas, yksinkertainen koodi ja optimoi tarvittaessa. Tämän viestin tarkoituksena oli tarjota sinulle nämä optimointityökalut, kun niitä todella tarvitset. Toivon että nautit siitä!

spot_img

Uusin älykkyys

spot_img

Keskustele kanssamme

Hei siellä! Kuinka voin olla avuksi?