My Prejšnja objava je bil širok pregled SvelteKita, kjer smo videli, kako odlično orodje je za spletni razvoj. Ta objava bo razkrila, kar smo naredili tam, in se poglobila v najljubšo temo vsakega razvijalca: predpomnjenje. Torej, ne pozabite prebrati moje zadnje objave, če je še niste. Koda za to objavo je na voljo na GitHubu, Pa tudi demo v živo.
Ta objava govori o ravnanju s podatki. Dodali bomo nekaj osnovne funkcije iskanja, ki bo spremenila poizvedbeni niz strani (z uporabo vgrajenih funkcij SvelteKit) in ponovno sprožila nalagalnik strani. Toda namesto da samo ponovno poizvedujemo po naši (namišljeni) zbirki podatkov, bomo dodali nekaj predpomnjenja, tako da bo ponovno iskanje prejšnjih iskanj (ali uporaba gumba za nazaj) hitro pokazalo predhodno pridobljene podatke iz predpomnilnika. Ogledali si bomo, kako nadzorovati čas, v katerem predpomnjeni podatki ostanejo veljavni, in, kar je še pomembneje, kako ročno razveljaviti vse predpomnjene vrednosti. Kot češnjo na torti si bomo ogledali, kako lahko ročno posodobimo podatke na trenutnem zaslonu, na strani odjemalca, po mutaciji, medtem ko še vedno čistimo predpomnilnik.
To bo daljša in težja objava kot večina tega, kar običajno pišem, saj obravnavamo težje teme. Ta objava vam bo v bistvu pokazala, kako implementirati skupne funkcije priljubljenih podatkovnih pripomočkov, kot je odzivna poizvedba; vendar namesto zunanje knjižnice bomo uporabljali samo spletno platformo in funkcije SvelteKit.
Na žalost so funkcije spletne platforme na nekoliko nižji ravni, zato bomo opravili nekoliko več dela, kot ste morda vajeni. Dobra stran je, da ne bomo potrebovali nobenih zunanjih knjižnic, kar bo pripomoglo k temu, da bodo velikosti paketov lepe in majhne. Prosim, ne uporabljajte pristopov, ki vam jih bom pokazal, razen če imate za to dober razlog. Pri predpomnjenju se je zlahka zmotiti in kot boste videli, bo koda vaše aplikacije nekoliko zapletena. Upajmo, da je vaša shramba podatkov hitra in da je vaš uporabniški vmesnik v redu, saj SvelteKitu omogoča, da vedno zahteva podatke, ki jih potrebuje za katero koli stran. Če je, ga pusti pri miru. Uživajte v preprostosti. Toda ta objava vam bo pokazala nekaj trikov, ko temu ne bo več tako.
Ko že govorimo o odzivni poizvedbi, je je bil pravkar izdan za Svelte! Če se torej zanašate na tehnike ročnega predpomnjenja veliko, obvezno preverite ta projekt in preverite, ali bi lahko pomagal.
Postavitev
Preden začnemo, naredimo nekaj majhnih sprememb kodo, ki smo jo imeli prej. To nam bo dalo izgovor, da vidimo nekatere druge funkcije SvelteKit in, kar je še pomembneje, nas bo pripravilo na uspeh.
Najprej premaknimo naše nalaganje podatkov iz našega nalagalnika +page.server.js
v Pot API. Ustvarili bomo a +server.js
datoteka v routes/api/todos
, in nato dodajte a GET
funkcijo. To pomeni, da bomo zdaj lahko pridobili (z uporabo privzetega glagola GET) v /api/todos
pot. Dodali bomo isto kodo za nalaganje podatkov kot prej.
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);
}
Nato vzemimo nalagalnik strani, ki smo ga imeli, in preprosto preimenujmo datoteko +page.server.js
do +page.js
(ali .ts
če ste svoj projekt prilagodili uporabi TypeScript). To spremeni naš nalagalnik tako, da postane "univerzalni" nalagalnik in ne nalagalnik strežnika. Dokumenti SvelteKit razložite razliko, vendar univerzalni nalagalnik deluje na strežniku in tudi na odjemalcu. Ena prednost za nas je, da fetch
klic v našo novo končno točko se bo izvajal neposredno iz našega brskalnika (po začetnem nalaganju), z uporabo izvornega brskalnika fetch
funkcijo. Čez nekaj časa bomo dodali standardno predpomnjenje HTTP, a zaenkrat bomo samo poklicali končno točko.
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, };
}
Zdaj pa našemu dodamo preprost obrazec /list
Stran:
<div class="search-form"> <form action="/sl/list"> <label>Search</label> <input autofocus name="search" /> </form>
</div>
Ja, obrazci lahko ciljajo neposredno na naše običajne nalagalnike strani. Zdaj lahko dodamo iskalni izraz v iskalno polje, zadetek Vnesite, poizvedbenemu nizu URL-ja pa bo dodan izraz »iskanje«, ki bo ponovno zagnal naš nakladalnik in preiskal naše elemente opravil.
Povečajmo tudi zamudo pri naših todoData.js
datoteka v /lib/data
. To bo olajšalo pregled nad tem, kdaj so podatki predpomnjeni in kdaj niso, ko delamo s to objavo.
export const wait = async amount => new Promise(res => setTimeout(res, amount ?? 500));
Ne pozabite, da je celotna koda za to objavo vse na GitHubu, če se morate sklicevati nanj.
Osnovno predpomnjenje
Začnimo z dodajanjem predpomnjenja našemu /api/todos
končna točka. Vrnili se bomo k našim +server.js
datoteko in dodamo našo prvo glavo za nadzor predpomnilnika.
setHeaders({ "cache-control": "max-age=60",
});
... zaradi česar bo celotna funkcija videti takole:
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);
}
Kmalu si bomo ogledali ročno razveljavitev, vendar ta funkcija pravi, da predpomni te klice API-ja za 60 sekund. To nastavite na karkoli želitein glede na vaš primer uporabe, stale-while-revalidate
bi bilo prav tako vredno pogledati.
In ravno tako se naše poizvedbe predpomnijo.
Opombe prepričaj se da odkljukajte potrditveno polje, ki onemogoči predpomnjenje v orodjih za razvijalce.
Ne pozabite, da če je vaša začetna navigacija v aplikaciji stran s seznamom, bodo ti rezultati iskanja interno predpomnjeni v SvelteKitu, zato ne pričakujte, da boste videli kaj v DevTools, ko se vrnete na to iskanje.
Kaj je predpomnjeno in kje
Naše prvo strežniško upodobljeno nalaganje naše aplikacije (ob predpostavki, da začnemo pri /list
stran) bodo prenesene na strežnik. SvelteKit bo te podatke serializiral in poslal naši stranki. Še več, opazoval bo Cache-Control
glava na odgovor in bo vedel uporabiti te predpomnjene podatke za ta klic končne točke v oknu predpomnilnika (ki smo ga v primeru postavitve nastavili na 60 sekund).
Po tem začetnem nalaganju, ko začnete iskati po strani, bi morali videti omrežne zahteve iz vašega brskalnika v /api/todos
seznam. Ko iščete stvari, ki ste jih že iskali (v zadnjih 60 sekundah), bi se morali odgovori naložiti takoj, saj so shranjeni v predpomnilniku.
Pri tem pristopu je še posebej kul to, da se lahko ti klici (odvisno od tega, kako upravljate z uničenjem predpomnilnika, ki si ga bomo ogledali) še naprej predpomnijo, tudi če znova naložite stran (za razliko od začetno nalaganje na strani strežnika, ki končno točko vedno pokliče sveže, tudi če je to storila v zadnjih 60 sekundah).
Očitno se lahko podatki kadar koli spremenijo, zato potrebujemo način za ročno čiščenje tega predpomnilnika, ki si ga bomo ogledali v nadaljevanju.
Razveljavitev predpomnilnika
Trenutno bodo podatki shranjeni v predpomnilniku za 60 sekund. Ne glede na vse bodo čez minuto iz naše podatkovne shrambe potegnjeni sveži podatki. Morda boste želeli krajše ali daljše časovno obdobje, toda kaj se zgodi, če mutirate nekaj podatkov in želite takoj počistiti predpomnilnik, da bo vaša naslednja poizvedba posodobljena? To bomo rešili tako, da URL-ju, ki ga pošljemo našemu novemu, dodamo vrednost za razbijanje poizvedb /todos
končna točka.
Shranimo to vrednost prekinitve predpomnilnika v piškotek. To vrednost je mogoče nastaviti na strežniku, vendar jo še vedno prebrati na odjemalcu. Poglejmo nekaj vzorčne kode.
Ustvarimo lahko a +layout.server.js
datoteko v samem korenu našega routes
mapo. To se bo zagnalo ob zagonu aplikacije in je odlično mesto za nastavitev začetne vrednosti piškotka.
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, };
}
Morda ste opazili isDataRequest
vrednost. Ne pozabite, da se bodo postavitve znova zagnale kadar koli kliče koda odjemalca invalidate()
, ali kadar koli izvedemo dejanje strežnika (ob predpostavki, da ne izklopimo privzetega vedenja). isDataRequest
označuje te ponovne zagone, zato nastavimo piškotek le, če je tako false
; v nasprotnem primeru pošljemo kar je že tam.
O httpOnly: false
pomembna je tudi zastava. To omogoča kodi naše stranke, da prebere te vrednosti piškotkov document.cookie
. To bi običajno predstavljalo varnostno skrb, vendar so v našem primeru to nesmiselne številke, ki nam omogočajo predpomnjenje ali razpad predpomnilnika.
Branje vrednosti predpomnilnika
Naš univerzalni nakladalnik je tisto, kar kliče naš /todos
končna točka. To se izvaja na strežniku ali odjemalcu in prebrati moramo to vrednost predpomnilnika, ki smo jo pravkar nastavili, ne glede na to, kje smo. Če smo na strežniku, je relativno enostavno: lahko pokličemo await parent()
da pridobite podatke iz nadrejenih postavitev. Toda na odjemalcu bomo morali uporabiti nekaj grobe kode za razčlenjevanje 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] ?? "";
};
Na srečo ga potrebujemo samo enkrat.
Pošiljanje vrednosti predpomnilnika
Toda zdaj moramo pošljite ta vrednost za naše /todos
končna točka.
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')
v njem preveri, ali smo na odjemalcu (s preverjanjem vrste dokumenta), in ne vrne ničesar, če smo, na tej točki vemo, da smo na strežniku. Nato uporabi vrednost iz naše postavitve.
Razbijanje predpomnilnika
Ampak kako ali dejansko posodobimo to vrednost prekinitve predpomnilnika, ko jo potrebujemo? Ker je shranjen v piškotku, ga lahko pokličemo takole iz katerega koli dejanja strežnika:
cookies.set("todos-cache", cacheValue, { path: "/", httpOnly: false });
Izvajanje
Od tod je vse navzdol; opravili smo težko delo. Pokrili smo različne primitive spletnih platform, ki jih potrebujemo, pa tudi, kam gredo. Zdaj pa se malo zabavajmo in napišimo kodo aplikacije, da vse skupaj povežemo.
Zaradi razlogov, ki bodo čez nekaj časa jasni, začnimo z dodajanjem funkcije urejanja v naše /list
strani. To drugo vrstico tabele bomo dodali za vsako opravilo:
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>
In seveda bomo morali dodati dejanje obrazca za naše /list
strani. Dejanja so lahko samo notranja .server
strani, zato bomo dodali a +page.server.js
v našem /list
mapo. (Da, a +page.server.js
datoteka lahko obstaja poleg a +page.js
mapa.)
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 }); },
};
Zagrabimo podatke iz obrazca, vsilimo zakasnitev, posodobimo naša opravila in nato, kar je najpomembneje, izbrišemo piškotek za prekinitev predpomnilnika.
Poskusimo to. Znova naložite svojo stran in nato uredite eno od opravil. Čez trenutek bi morali videti posodobljeno vrednost tabele. Če pogledate na zavihek Omrežje v orodju DevToold, boste videli prenos v /todos
končna točka, ki vrne vaše nove podatke. Enostavno in privzeto deluje.
Takojšnje posodobitve
Kaj pa, če se želimo izogniti pridobivanju, ki se zgodi, ko posodobimo svoj element opravila, in namesto tega posodobimo spremenjeni element kar na zaslonu?
To ni samo vprašanje uspešnosti. Če iščete »objavo« in nato odstranite besedo »objava« s katerega koli elementa opravil na seznamu, bodo po urejanju izginili s seznama, saj niso več v rezultatih iskanja na tej strani. UX bi lahko izboljšali z nekaj okusne animacije za razburljiva opravila, a recimo, da smo želeli ne znova zaženite funkcijo nalaganja te strani, vendar še vedno počistite predpomnilnik in posodobite spremenjena opravila, da lahko uporabnik vidi urejanje. SvelteKit to omogoča – poglejmo, kako!
Najprej naredimo eno majhno spremembo našega nakladalnika. Namesto da vrnemo naše opravke, vrnimo a pisljiva trgovina ki vsebuje naše naloge.
return { todos: writable(todos),
};
Prej smo do opravil dostopali na data
prop, ki ni v naši lasti in ga ne moremo posodobiti. Toda Svelte nam dovoli, da naše podatke vrnemo v njihovo lastno trgovino (ob predpostavki, da uporabljamo univerzalni nalagalnik, kar tudi je). Narediti moramo samo še eno prilagoditev /list
stran.
Namesto tega:
{#each todos as t}
… to moramo storiti od takrat todos
je sama zdaj trgovina.:
{#each $todos as t}
Zdaj se naši podatki nalagajo kot prej. Toda odkar todos
je pisljiva trgovina, jo lahko posodobimo.
Najprej zagotovimo funkcijo za našo use:enhance
atribut:
<form use:enhance={executeSave} on:submit={runInvalidate} method="post" action="?/editTodo"
>
To se bo zagnalo pred oddajo. Zapišimo naslednje:
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; } }) ); };
}
Ta funkcija zagotavlja a data
objekt z našimi podatki obrazca. mi vrnitev asinhrono funkcijo, ki se bo izvajala po naše urejanje je končano. Dokumenti pojasniti vse to, vendar s tem izklopimo privzeto obdelavo obrazcev SvelteKit, ki bi ponovno zagnala naš nalagalnik. To je točno to, kar si želimo! (To privzeto vedenje bi lahko preprosto vrnili nazaj, kot pojasnjujejo dokumenti.)
Zdaj kličemo update
na našem todos
niz, saj je trgovina. In to je to. Po urejanju elementa opravila se naše spremembe takoj prikažejo in naš predpomnilnik je počiščen (kot prej, saj smo v našem editTodo
dejanje oblike). Torej, če iščemo in se nato pomaknemo nazaj na to stran, bomo dobili sveže podatke iz našega nalagalnika, ki bo pravilno izključil vse posodobljene elemente opravil, ki so bili posodobljeni.
Koda za takojšnje posodobitve je na voljo na GitHubu.
Kopanje globlje
Piškotke lahko nastavimo v kateri koli funkciji nalaganja strežnika (ali dejanju strežnika), ne le v korenski postavitvi. Torej, če se nekateri podatki uporabljajo samo pod eno samo postavitvijo ali celo eno stranjo, lahko to vrednost piškotka nastavite tam. Še več, če ste ne izvedete trik, ki sem ga pravkar pokazal, ročno posodabljanje podatkov na zaslonu in namesto tega želite, da se vaš nakladalnik po mutaciji znova zažene, potem lahko vedno nastavite novo vrednost piškotka kar v tej funkciji nalaganja brez kakršnega koli preverjanja isDataRequest
. Na začetku se bo nastavil, nato pa bo vsakič, ko boste zagnali strežniško dejanje, ta postavitev strani samodejno razveljavila in znova priklicala vaš nalagalnik, pri čemer bo ponovno nastavljen niz za prekinitev predpomnilnika, preden bo poklican vaš univerzalni nalagalnik.
Pisanje funkcije za ponovno nalaganje
Zaključimo z izdelavo še zadnje funkcije: gumba za ponovno nalaganje. Dajmo uporabnikom gumb, ki bo počistil predpomnilnik in nato znova naložil trenutno poizvedbo.
Dodali bomo preprosto dejanje obrazca:
async reloadTodos({ cookies }) { cookies.set('todos-cache', +new Date(), { path: '/', httpOnly: false });
},
V resničnem projektu verjetno ne bi kopirali/prilepili iste kode za nastavitev istega piškotka na enak način na več mestih, vendar bomo za to objavo optimizirali za preprostost in berljivost.
Zdaj pa ustvarimo obrazec za objavo v njem:
<form method="POST" action="?/reloadTodos" use:enhance> <button>Reload todos</button>
</form>
To deluje!
Temu bi lahko rekli, da je končano, in gremo naprej, vendar to rešitev nekoliko izboljšajmo. Natančneje, posredujmo povratne informacije na strani, da bi uporabniku povedali, da poteka ponovno nalaganje. Poleg tega so dejanja SvelteKit privzeto razveljavljena vse. Vsaka postavitev, stran itd. v hierarhiji trenutne strani bi se znova naložila. Morda so nekateri podatki, ki so enkrat naloženi v korenski postavitvi in nam jih ni treba razveljaviti ali znova naložiti.
Torej, osredotočimo se na stvari in znova naložimo svoja opravila šele, ko pokličemo to funkcijo.
Najprej posredujmo funkcijo za izboljšanje:
<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; }); };
};
Postavljamo novo reloading
spremenljivka do true
pri Začetek tega dejanja. In potem, da bi preglasili privzeto vedenje razveljavitve vsega, vrnemo an async
funkcijo. Ta funkcija se bo zagnala, ko bo končano dejanje našega strežnika (ki samo nastavi nov piškotek).
Brez tega async
funkcija vrnila, bi SvelteKit razveljavil vse. Ker zagotavljamo to funkcijo, ne bo ničesar razveljavila, zato je na nas, da ji povemo, kaj naj znova naloži. To počnemo z invalidate
funkcijo. Imenujemo ga z vrednostjo reload:todos
. Ta funkcija vrne obljubo, ki se razreši, ko je razveljavitev končana, na katero točko nastavimo reloading
nazaj false
.
Nazadnje moramo naš nalagalnik sinhronizirati s tem novim reload:todos
vrednost razveljavitve. To naredimo v našem nakladalniku z depends
funkcija:
export async function load({ fetch, url, setHeaders, depends }) { depends('reload:todos'); // rest is the same
In to je to. depends
in invalidate
so neverjetno uporabne funkcije. Kar je kul je to invalidate
ne vzame samo poljubnih vrednosti, ki jih posredujemo, kot smo jih mi. Zagotovimo lahko tudi URL, ki mu bo SvelteKit sledil, in razveljavil vse nalagalnike, ki so odvisni od tega URL-ja. V ta namen, če se sprašujete, ali lahko preskočimo klic na depends
in razveljavi naše /api/todos
končno točko, lahko, vendar morate zagotoviti točno URL, vključno z search
izraz (in našo vrednost predpomnilnika). Torej lahko sestavite URL za trenutno iskanje ali pa se ujemate z imenom poti, takole:
invalidate(url => url.pathname == "/api/todos");
Osebno najdem rešitev, ki uporablja depends
bolj eksplicitno in preprosto. Ampak glej dokumenti seveda za več informacij in se odločite sami.
Če želite videti gumb za ponovno nalaganje v akciji, je koda zanj to vejo repo.
Ločitvene misli
To je bila dolga objava, a upajmo, da ne preveč. Poglobili smo se v različne načine, kako lahko predpomnimo podatke, ko uporabljamo SvelteKit. Velik del tega je šlo le za uporabo primitivov spletne platforme za dodajanje pravilnega predpomnilnika in vrednosti piškotkov, katerih poznavanje vam bo služilo pri spletnem razvoju na splošno, ne le pri SvelteKitu.
Poleg tega je to nekaj, kar absolutno ne potrebujejo ves čas. Verjetno bi morali te vrste naprednih funkcij poseči le, ko jih dejansko potrebujejo. Če vaša podatkovna shramba streže podatke hitro in učinkovito in nimate opravka s kakršnimi koli težavami s skaliranjem, nima smisla napihnjevati kode aplikacije z nepotrebno zapletenostjo pri izvajanju stvari, o katerih smo govorili tukaj.
Kot vedno napišite jasno, čisto in preprosto kodo in po potrebi optimizirajte. Namen te objave je bil zagotoviti ta orodja za optimizacijo, ko jih resnično potrebujete. Upam, da ste uživali!
- Distribucija vsebine in PR s pomočjo SEO. Okrepite se še danes.
- Platoblockchain. Web3 Metaverse Intelligence. Razširjeno znanje. Dostopite tukaj.
- vir: https://css-tricks.com/caching-data-in-sveltekit/
- 1
- 11
- 7
- 9
- 98
- a
- Sposobna
- O meni
- absolutno
- Dostop
- Ukrep
- dejavnosti
- dejansko
- napredno
- Prednost
- po
- proti
- vsi
- Dovoli
- omogoča
- sam
- že
- vedno
- znesek
- in
- animacija
- API
- aplikacija
- uporaba
- pristop
- pristopi
- Array
- samodejno
- Na voljo
- čakati
- nazaj
- postanejo
- pred
- počutje
- Boljše
- Poleg
- Bit
- Pasovi
- Branch
- široka
- brskalnik
- Building
- vgrajeno
- Sveženj
- bankrot
- Gumb
- Cache
- torta
- klic
- se imenuje
- poziva
- ne more
- primeru
- spremenite
- Spremembe
- preveriti
- preverjanje
- jasno
- Obračun
- stranke
- Koda
- Skupno
- dokončanje
- kompleksnost
- Skrb
- naprej
- nadzor
- piškotki
- Cool
- bi
- Tečaj
- zajeti
- kritje
- ustvarjajo
- Trenutna
- datum
- Baze podatkov
- Datum
- deliti
- privzeto
- zamuda
- Odvisno
- odvisno
- dev
- Razvoj
- DID
- težko
- neposredno
- dokument
- Ne
- tem
- dont
- navzdol
- vsak
- enostavno
- učinkovito
- bodisi
- Končna točka
- uživajte
- zlasti
- v bistvu
- itd
- Tudi
- Tudi vsak
- vse
- točno
- Primer
- Izhod
- pričakovati
- Pojasnite
- izvoz
- zunanja
- FAST
- Priljubljeni
- Feature
- Lastnosti
- povratne informacije
- Preneseno
- Nekaj
- file
- Najdi
- konec
- prva
- Osredotočite
- vilice
- obrazec
- Obrazci
- sveže
- iz
- polno
- zabava
- funkcija
- funkcionalnost
- funkcije
- splošno
- dobili
- Daj
- dana
- Go
- dogaja
- dobro
- veliko
- bruto
- Ravnanje
- se zgodi
- Trdi
- Trdo delo
- pomoč
- tukaj
- skrita
- hierarhija
- hit
- upam,
- upajmo, da
- Kako
- Kako
- HTML
- HTTPS
- ID
- namišljena
- Takojšen
- takoj
- izvajati
- uvoz
- izboljšanje
- in
- Vključno
- Povečajte
- neverjetno
- označuje
- info
- začetna
- na začetku
- vhod
- Namesto
- IT
- Izdelkov
- sam
- JavaScript
- json
- Imejte
- Otrok
- Vedite
- znanje
- Zadnja
- postavitev
- pustite
- dolžina
- Lets
- Stopnja
- knjižnice
- Knjižnica
- Seznam
- malo
- v živo
- obremenitev
- nakladač
- nalaganje
- obremenitve
- Long
- več
- Poglej
- si
- iskanje
- Znamka
- IZDELA
- upravljanje
- Navodilo
- ročno
- Stave
- Matter
- pomeni
- morda
- min
- spremembe
- spremenite
- Trenutek
- več
- Najbolj
- premikanje
- Mozilla
- več
- Ime
- materni
- Krmarjenje
- ostalo
- potrebno
- Nimate
- Ni treba
- potrebe
- mreža
- Novo
- Naslednja
- normalno
- Običajno
- številke
- predmet
- opazujejo
- ONE
- optimizacija
- Optimizirajte
- Da
- Ostalo
- drugače
- pregled
- lastne
- deli
- pot
- popolna
- popoln kraj
- performance
- Obdobje
- Kraj
- Mesta
- platforma
- Platforme
- platon
- Platonova podatkovna inteligenca
- PlatoData
- Točka
- Popular
- mogoče
- Prispevek
- prej
- Predhodna
- verjetno
- Težave
- Projekt
- Obljuba
- zagotavljajo
- zagotavlja
- zagotavljanje
- vlečenje
- Namen
- dal
- hitro
- dosežejo
- Preberi
- pravo
- Razlog
- Razlogi
- relativno
- ne pozabite
- odstrani
- zahteva
- zahteva
- Odgovor
- REST
- povzroči
- Rezultati
- vrnitev
- vrnitev
- vrne
- koren
- ROW
- Run
- Enako
- shranjevanje
- skaliranje
- Zaslon
- Iskalnik
- iskanje
- drugi
- sekund
- varnost
- Občutek
- služijo
- služijo
- nastavite
- Kompleti
- nastavitev
- Kmalu
- shouldnt
- Prikaži
- pomemben
- Enostavno
- preprostost
- preprosto
- saj
- sam
- velikosti
- majhna
- So
- Rešitev
- SOLVE
- nekaj
- Nekaj
- posebej
- standardna
- Začetek
- začel
- zagon
- Še vedno
- Postanki
- trgovina
- shranjeni
- predloži
- uspeh
- miza
- Bodite
- ciljna
- TD
- tehnike
- O
- njihove
- Tukaj.
- stvari
- skozi
- KRAVATA
- čas
- Naslov
- do
- skupaj
- orodje
- orodja
- temo
- Teme
- sledenje
- Res
- OBRAT
- Tipkovnica
- ui
- Universal
- Nadgradnja
- posodobljeno
- posodobitve
- posodabljanje
- Upside
- URL
- us
- uporaba
- primeru uporabe
- uporabnik
- Uporabniki
- navadno
- javne gospodarske službe
- ux
- vrednost
- Vrednote
- različnih
- preko
- Počakaj
- hotel
- načini
- web
- Izdelava spletnih strani
- Kaj
- ali
- ki
- medtem
- celoti
- bo
- v
- brez
- spraševati
- beseda
- delo
- deluje
- vredno
- bi
- pisati
- Napačen
- Vi
- Vaša rutina za
- sami
- zefirnet