[{"data":1,"prerenderedAt":298},["ShallowReactive",2],{"blog-\u002Fpl\u002Fblog\u002F2024\u002Fpokedex-kilkadziesiat-zapytan-zamiast-tysiaca":3,"blog-project-\u002Fpl\u002Fblog\u002F2024\u002Fpokedex-kilkadziesiat-zapytan-zamiast-tysiaca":184},{"id":4,"title":5,"art":6,"body":7,"date":166,"description":167,"draft":168,"extension":169,"image":170,"kind":171,"meta":172,"navigation":173,"ogImage":174,"path":175,"project":176,"seo":177,"slug":170,"stem":178,"tags":179,"__hash__":183},"blog_pl\u002Fpl\u002Fblog\u002F2024\u002Fpokedex-kilkadziesiat-zapytan-zamiast-tysiaca.md","Pokedex – kilkadziesiąt zapytań zamiast ponad tysiąca","\u002Fart\u002Fblog\u002Fpokedex.svg",{"type":8,"value":9,"toc":157},"minimark",[10,14,17,22,25,28,41,53,57,75,78,85,89,92,107,110,114,117,128,132,146],[11,12,13],"p",{},"Pokedex to mój pierwszy większy projekt w JavaScripcie. Pisałem go równolegle z kursem – bez frameworka, na własnych klasach. Chciałem zrobić coś trudniejszego niż kolejną listę zadań i coś, czego nie znalazłem gotowego.",[11,15,16],{},"Pokemony wybrałem z prostego powodu: są od lat, więc ktoś na pewno zbudował już dla nich API. Tak było – PokéAPI wyskoczyło w wyszukiwarce jako pierwsze. Dane wprowadza ktoś inny, a ja mogłem skupić się na kodzie.",[18,19,21],"h2",{"id":20},"problem-dane-są-w-wielu-miejscach","Problem: dane są w wielu miejscach",[11,23,24],{},"W PokéAPI każdy pokemon ma swój adres z kompletem danych. Najprostsza droga to jedno zapytanie na pokemona – tak robi większość tutoriali z pierwszą generacją. Przy ponad 1000 gatunków to ponad 1000 zapytań przy każdym wejściu na stronę. Bałem się, że to zbyt mocno obciąży serwer, a strona będzie się długo ładować.",[11,26,27],{},"Dlatego odwróciłem kolejność. Zamiast pytać każdego pokemona o jego typ, pytam każdy typ o jego pokemony:",[29,30,31,35,38],"ol",{},[32,33,34],"li",{},"lista gatunków – jedno zapytanie daje numery i nazwy wszystkich pokemonów,",[32,36,37],{},"typy – każdy typ zwraca listę pokemonów, które go mają,",[32,39,40],{},"generacje – każda generacja zwraca listę swoich gatunków.",[11,42,43,44,48,49,52],{},"Zapytania o typy i generacje idą równolegle przez ",[45,46,47],"code",{},"Promise.all",". Do tego osobne zapytania o nazwy z myślnikiem – API zwraca np. ",[45,50,51],{},"mr-mime",", a na liście chciałem mieć „Mr. Mime”. W sumie wychodzi kilkadziesiąt zapytań zamiast ponad tysiąca.",[18,54,56],{"id":55},"mała-baza-w-przeglądarce","Mała baza w przeglądarce",[11,58,59,60,63,64,63,67,70,71,74],{},"Z tych odpowiedzi składam jeden obiekt: numer pokemona → nazwa, typy i generacja. Klucze są jednoliterowe (",[45,61,62],{},"n",", ",[45,65,66],{},"t",[45,68,69],{},"g","), bo całość trafia do ",[45,72,73],{},"localStorage",", a tam miejsce jest ograniczone.",[11,76,77],{},"Przy kolejnej wizycie strona pyta API tylko o to, ile jest teraz gatunków. Jeśli liczba zgadza się z tą w pamięci, lista ładuje się z przeglądarki – to dwa zapytania zamiast kilkudziesięciu. Jeśli w API pojawią się nowe pokemony, baza zbuduje się od nowa sama. Tego chciałem od początku: żeby raz napisany kod działał dalej beze mnie.",[11,79,80,81,84],{},"Wzrost, waga i statystyki pobieram dopiero wtedy, gdy ktoś otworzy kartę pokemona. Trafiają do ",[45,82,83],{},"sessionStorage",", więc drugie otwarcie tej samej karty nie wysyła już zapytania.",[18,86,88],{"id":87},"co-chwilę-nowy-pomysł","Co chwilę nowy pomysł",[11,90,91],{},"Sama lista szybko mi nie wystarczyła. W trakcie pisania co chwilę chciałem coś dodać:",[93,94,95,98,101,104],"ul",{},[32,96,97],{},"zaznaczanie złapanych pokemonów – lista zapisuje się w przeglądarce,",[32,99,100],{},"import i eksport tej listy, żeby przenieść ją na inne urządzenie albo do innej przeglądarki,",[32,102,103],{},"jasny i ciemny motyw,",[32,105,106],{},"paginację z numerem strony w adresie, żeby link prowadził od razu w to samo miejsce.",[11,108,109],{},"Pomysłów było więcej niż czasu. Często zaczynałem kolejną rzecz, zanim poprzednia działała do końca tak, jak powinna – i potem wracałem do kilku miejsc naraz.",[18,111,113],{"id":112},"błędy-które-uczyły-najwięcej","Błędy, które uczyły najwięcej",[11,115,116],{},"Na początku kilka razy wpadłem w pętlę, która przeciążała komputer. Potem przyszła asynchroniczność – musiałem sprawdzać, gdzie wysyłam zapytanie, co dostaję i czy te dane w ogóle są mi potrzebne. Najtrudniejsze okazało się zgranie tego z DOM-em: dane już są, a widok jeszcze nie, albo odwrotnie.",[11,118,119,120,123,124,127],{},"Moim głównym narzędziem był ",[45,121,122],{},"console.log"," i ",[45,125,126],{},"console.trace",". Dziś częściej zatrzymałbym kod w debuggerze w miejscu, gdzie coś się dzieje – wtedy tego nie robiłem, a pewnie zaoszczędziłbym sporo czasu.",[18,129,131],{"id":130},"co-zrobiłbym-dziś-inaczej","Co zrobiłbym dziś inaczej",[93,133,134,137,140,143],{},[32,135,136],{},"Kończyłbym jedną funkcję, zanim zacznę następną. Do pracy małymi krokami doszedłem dopiero po jakimś czasie.",[32,138,139],{},"Najpierw przeanalizowałbym, jak API podaje dane i czego naprawdę potrzebuję, a dopiero potem pisał kod.",[32,141,142],{},"Może najpierw zrobiłbym wygląd, a potem funkcje – wygląd zmieniałem wiele razy w trakcie.",[32,144,145],{},"Nie wszystko musi być klasą. Niektóre części dziś napisałbym jako zwykłe funkcje.",[11,147,148,149,156],{},"Projekt nie wygląda na wielki, ale dla mnie był ważnym krokiem. Kiedyś chcę przepisać go na Vue – temat ten sam, nowa lekcja. Na razie ",[150,151,155],"a",{"href":152,"rel":153},"https:\u002F\u002Flukaszdzielo.github.io\u002Fpokedex\u002F",[154],"nofollow","Pokedex działa tutaj",".",{"title":158,"searchDepth":159,"depth":159,"links":160},"",2,[161,162,163,164,165],{"id":20,"depth":159,"text":21},{"id":55,"depth":159,"text":56},{"id":87,"depth":159,"text":88},{"id":112,"depth":159,"text":113},{"id":130,"depth":159,"text":131},"2024-03-20","Jak w czystym JavaScripcie zbudowałem Pokedex na ponad 1000 pokemonów – z kolejnością pobierania danych z PokéAPI i małą bazą w przeglądarce.",false,"md",null,"post",{},true,"\u002Fog\u002Fblog\u002Fpokedex-pl.jpg","\u002Fpl\u002Fblog\u002F2024\u002Fpokedex-kilkadziesiat-zapytan-zamiast-tysiaca","\u002Fprojects\u002F2024\u002Fpokedex",{"title":5,"description":167},"pl\u002Fblog\u002F2024\u002Fpokedex-kilkadziesiat-zapytan-zamiast-tysiaca",[180,181,182],"javascript","pokeapi","projekt","GDtFhO8YHaQMS30tJW0HJpKQA0PnTfPZTZHbvo54bNg",{"id":185,"title":186,"agency":170,"body":187,"compare":170,"cover":242,"date":248,"description":249,"draft":168,"extension":169,"facts":250,"featured":168,"gallery":264,"galleryLead":170,"highlights":170,"image":280,"links":281,"meta":283,"navigation":173,"note":170,"ogImage":284,"path":285,"seo":286,"stack":287,"stem":293,"tags":294,"__hash__":297},"projects_pl\u002Fpl\u002Fprojects\u002F2024\u002Fpokedex\u002Findex.md","Pokedex",{"type":8,"value":188,"toc":239},[189,192,196],[11,190,191],{},"Interaktywna encyklopedia pokemonów obsługująca ponad 1000 stworzeń – napisana w czystym JavaScript (ES6+, wzorce OOP), bez frameworków, w oparciu o publiczne PokéAPI.",[18,193,195],{"id":194},"najważniejsze-cechy","Najważniejsze cechy",[93,197,198,203,214,230,233,236],{},[32,199,200,201],{},"Przemyślana kolejność ładowania danych z PokéAPI – równoległe zapytania przez ",[45,202,47],{},[32,204,205,206,209,210,213],{},"Lokalna baza w przeglądarce (",[45,207,208],{},"LocalStorage"," + ",[45,211,212],{},"SessionStorage",") – raz pobrane dane nie idą drugi raz do API",[32,215,216,217,63,220,63,223,63,226,229],{},"Modułowa architektura klas (",[45,218,219],{},"DataManager",[45,221,222],{},"DataBuilder",[45,224,225],{},"StorageManager",[45,227,228],{},"PokemonDialog",") przygotowana pod migrację do Vue 3",[32,231,232],{},"Responsywna, dwukierunkowo synchronizowana paginacja z odwzorowaniem stanu w URL",[32,234,235],{},"Jasny i ciemny motyw (też automatyczny, według ustawień systemu)",[32,237,238],{},"Złapane pokemony – zaznaczanie w karcie pokemona, import i eksport listy w ustawieniach",{"title":158,"searchDepth":159,"depth":159,"links":240},[241],{"id":194,"depth":159,"text":195},{"desktop":243,"phone":244,"width":245,"height":246,"alt":247},"\u002Fprojects\u002F2024\u002Fpokedex\u002Flist.webp","\u002Fprojects\u002F2024\u002Fpokedex\u002Fphone.webp",1920,1105,"Pokedex – lista pokemonów z paginacją","2024-01-28","Interaktywny Pokedex na ponad 1000 pokemonów w czystym JavaScript (OOP), oparty o PokéAPI – z przemyślaną kolejnością ładowania danych i lokalną bazą w przeglądarce.",[251,254,257,261],{"value":252,"text":253},"2024","rok realizacji",{"value":255,"text":256},"Solo","projekt własny – od pomysłu po wdrożenie",{"value":258,"suffix":259,"text":260},"1000","+","pokemonów z PokéAPI – kilkadziesiąt zapytań zamiast ponad 1000",{"value":262,"text":263},"Vanilla JS","bez Vue, Reacta i innych frameworków – własne klasy w czystym JavaScript",[265,268,272,276],{"src":243,"width":245,"height":246,"alt":266,"caption":267},"Lista pokemonów z paginacją","Lista – ponad 1000 pokemonów, numer strony zapisany w adresie (?p=)",{"src":244,"device":269,"alt":270,"caption":271},"phone","Pokedex na telefonie – karta pokemona","Telefon – karta pokemona otwarta nad listą w dwóch kolumnach",{"src":273,"width":245,"height":246,"alt":274,"caption":275},"\u002Fprojects\u002F2024\u002Fpokedex\u002Fpokemon-card.webp","Okno szczegółów pokemona","Karta pokemona – nazwa, typy i generacja od razu z pamięci, statystyki dociągane z API",{"src":277,"width":245,"height":246,"alt":278,"caption":279},"\u002Fprojects\u002F2024\u002Fpokedex\u002Fsettings.webp","Ustawienia aplikacji","Ustawienia – motyw, import i eksport złapanych pokemonów, czyszczenie danych","\u002Fprojects\u002F2024\u002Fpokedex\u002Fthumbnail.webp",{"live":152,"github":282},"https:\u002F\u002Fgithub.com\u002Flukaszdzielo\u002Fpokedex",{},"\u002Fog\u002Fprojects\u002Fpokedex-pl.jpg","\u002Fpl\u002Fprojects\u002F2024\u002Fpokedex",{"title":186,"description":249},[288,289,290,208,291,292],"JavaScript (ES6+)","OOP","PokéAPI","SCSS","bez frameworków","pl\u002Fprojects\u002F2024\u002Fpokedex\u002Findex",[180,295,296,181],"vanilla-js","oop","QDnaD_4RdWuPYQhpAwf3gAy2Nc7QEFWafQfT-QnxFRI",1791981943745]