Jak zmniejszyłem rozmiar mojej strony konfiguracyjnej IoT 11 razy, używając Javascript zamiast HTML
Poniżej pokażę jak zredukowałem rozmiar strony HTML z konfiguracją pinów urządzenia IoT z około 90kB do zaledwie 8kB dzięki zamianie statycznego HTML na skrypt JS, który go generuje. Użyję mojego projektu OpenBeken jako przykładu, ale ogólny pomysł pokazany tutaj można łatwo zastosować do dowolnego innego środowiska tworzącego strony HTML z kodu C (lub podobnego). Ten temat zakłada, że użytkownik zna podstawy C, HTML i Javascript...
W tym temacie odnoszę się do strony konfiguracyjnej OBK, która pozwala ustawić role GPIO na listach rozwijanych:
Wcześniej rozmiar tej strony przekraczał 90 000 bajtów:
Powodowało to powolne ładowanie na wielu platformach.
Po zmianie rozmiar wynosi teraz:
Zacznijmy od sprawdzenia, dlaczego rozmiar strony jest tak duży w przypadku tej konfiguracji. Możemy po prostu wyświetlić źródło strony w przeglądarce:
Teraz wyraźnie widać, że dla każdego z rozwijanych menu lista opcji jest powtarzana. Jest to bardzo proste, ale też nieoptymalne. Powtarza się to dla każdego GPIO, więc jeśli na przykładowej platformie jest 30 dostępnych pinów IO, to powtarza się to 30 razy!
Krótkie spojrzenie na kod OBK potwierdza, że tak właśnie się dzieje:
Kod: C / C++
Poniższe jest wykonywane dla każdego możliwego pinu! Musimy to zoptymalizować...
Aby to zoptymalizować, użyjemy Javascript. W JS utworzymy jedną, globalną tablicę ról pinów , a następnie dla każdego dropdown wstawimy do niej elementy za pomocą skryptu. Są jednak dwa problemy do rozwiązania:
- musimy również ustawić aktywny wybrany element, aby ludzie nie tracili ustawień przy każdym odświeżeniu i zapisaniu
- musimy wykluczyć role PWM dla pinów innych niż PWM.
Zignorujmy na razie kwestię PWM. Zacznijmy od następującego szkicu:
Kod: Javascript
Tablica r jest listą nazw ról elementów. W mojej funkcji f, iteruję nazwy ról pinezek i dodaję je do listy rozwijanej d. Tam również sprawdzam wybraną rolę, której indeks musi być podany podczas wywoływania funkcji f.
Indeks wybranej roli można łatwo pobrać z kodu OBK, ale dla odniesienia do obiektu select DOM musiałem dalej modyfikować kod. Zdecydowałem się na pobieranie go przez ID:
Kod: Javascript
Teraz, gdy mamy już podstawy, zastanówmy się również, jak możemy pominąć role PWM dla pinów innych niż PWM. OBK już wie, które piny obsługują PWM, więc możemy po prostu przekazać dodatkowy argument, a następnie sprawdzić, czy rola pinu zaczyna się od PWM, chociaż w przyszłości mogę po prostu zakodować indeks roli (będzie krótszy o kilka znaków). Zauważ, że zmienna "b" jest dodatkowym argumentem, który dodałem do funkcji:
Kod: Javascript
Ostatecznie zmodyfikowałem mój kod C, aby po prostu wydrukować następujący skrypt podczas generowania strony OBK, oczywiście zastępując również fałszywe dane rzeczywistymi rolami pinów OBK:
To działa i rozmiar strony zmniejszył się 9-krotnie, ale czy to wszystko co możemy zrobić?
Krótki rzut oka na kod HTML pokazuje, że wciąż jest miejsce na poprawę:
Generowanie div indeksu kanału może być również proceduralne. Oto upiększona wersja nowego kodu, który również generuje div:
Kod: Javascript
Tworzenie div można by faktycznie wydzielić do innej funkcji, tak jak jest to robione dwa razy, ale nie sądzę, że dałoby mi to znaczną liczbę znaków.
Więc teraz rozmiar strony spadł do 8kB:
Podsumowując - generowanie kodu HTML z C jest bardzo proste, ale też niezbyt optymalne. W przypadku powtarzających się danych, takich jak dropdowny z tymi samymi opcjami, wydajniej jest wygenerować Javascript, który później wygeneruje elementy HTML. Dla mnie dało to poprawę o ponad jeden rząd wielkości pod względem zajmowanego miejsca. Naprawiło to również problemy z OBK, miejmy nadzieję...
Tę samą zasadę można zastosować również do innych projektów IoT, te same problemy mogą wystąpić na ESP i mogą być również rozwiązane w ESP poprzez generowanie HTML + JS zamiast czystego HTML, więc mam nadzieję, że każdy się czegoś nauczył.
Moją próbkę można oczywiście jeszcze ulepszyć, również za pomocą skryptów kompresujących Javascript, ale myślę, że optymalizacja, którą udało mi się uzyskać do tej pory, jest wystarczająca dla naszego projektu.
Przy okazji, jeśli czyta to jakiś użytkownik OBK, proszę sprawdź to i daj mi znać. Czy możesz sprawdzić, jak działa Twoja strona pinów (szczególnie w Firefoksie), a następnie zaktualizować do wersji testowej:
https://github.com/openshwprojects/OpenBK7231T_App/pull/1215
czy strona ładuje się teraz szybciej? Czy lepiej? @divadiow @max4elektroda @dedamraz @miegapele ? Czy możesz przetestować to na wielu platformach OBK?
UWAGA: Obk zapewnia również ustawienie pinów w aplikacji internetowej, więc poniższa strona nie jest kluczowa, ale nadal dobrze jest mieć ją dobrze działającą.
Komentarze
Miałem jeden konkretny moduł N, który całkowicie zawieszał się, gdy przechodziłem do pinów konfiguracyjnych, to rozwiązało ten problem! Przed: https://obrazki.elektroda.pl/7154115700_1715443251_thumb.jpg... [Czytaj dalej]
Działa tutaj na moim LN882H, strona ładuje się szybko (ale szczerze mówiąc, nie pamiętam, jak było wcześniej) Po szybkim spojrzeniu możesz nawet zaoszczędzić trochę więcej bajtów. Widzę kilka białych... [Czytaj dalej]
Właściwie mam LN882H działający w tej chwili ze starszą wersją. Wygląda na to, że stara wersja również działa bardzo dobrze. Nie ma zauważalnego spowolnienia w starszej wersji. Testowałem zarówno Chrome,... [Czytaj dalej]
Naprawdę dobry pomysł i ogromna poprawa! Z ciekawości: Nie spodziewam się zbyt dużej poprawy rozmiaru obrazu? Chodzi mi o to, że było dużo kodu HTML, ale większość była tworzona w pętlach, IIRC. [Czytaj dalej]
Nie sprawdzałem rozmiaru pamięci flash przed zmianą (główny system wydań wydaje się mieć obecnie pewne problemy), ale powiedziałbym, że zmiana rozmiaru pamięci flash jest bardzo, bardzo mała. Należy pamiętać,... [Czytaj dalej]
Mogę zasugerować małe "ulepszenie" (to kwestia "stylu" vs "rozmiaru"): Jeśli zmienisz function f(alias, id, c, b, ch1, ch2) { let f = document.getElementById("x"); ... [Czytaj dalej]
To dobra zmiana, możemy ją dodać, nie ma problemu. Pytanie tylko, czy nie możemy po prostu użyć jednego z istniejących stylów? A może proponowane rozwiązanie jest najkrótsze? [Czytaj dalej]
Szczerze mówiąc byłem zbyt leniwy, aby spróbować zagłębić się w style, być może możliwe byłoby ponowne użycie innego, ale ponieważ potrzebowalibyśmy klasy, prawdopodobnie nie byłoby to dużo krótsze... ... [Czytaj dalej]
Pole drugiego kanału jest obecnie wyświetlane tylko wtedy, gdy rola pinu je obsługuje. Na przykład przycisk może mieć dwa powiązane kanały - jeden dla pojedynczego kliknięcia, drugi dla podwójnego kliknięcia.... [Czytaj dalej]
Czy byłoby możliwe, aby drugie pole kanału ujawniało się natychmiast po wybraniu obsługiwanego urządzenia, zamiast konieczności zapisywania w celu ujawnienia drugiego pola, a następnie ponownego zapisywania... [Czytaj dalej]
Oczywiście, ale wymagałoby to przechowywania drugiej tablicy z liczbą kanałów, których wymaga dana rola pinu, a następnie przechwytywania zdarzenia onChange listy rozwijanej, aby można było tam zmienić... [Czytaj dalej]
Nie mogę powiedzieć, że naprawdę zauważyłem spowolnienie, ale wszystkie są szybkie, a strona ładuje się dobrze. chrom. https://obrazki.elektroda.pl/3885064200_1715521417_thumb.jpg https://obrazki.elektroda.pl/5707795900_1715521449_thumb.jpg... [Czytaj dalej]
Próbowałem to zaimplementować w PR #1228 Tylko jako pierwszy pomysł, który wpadł mi do głowy podczas tej pracy: W tej chwili mamy właściwości roli IO w kilku miejscach: - mamy enum "main" ioRole_e... [Czytaj dalej]
Dobra robota! [Czytaj dalej]
Bardzo dobrze, Za chwilę to scalę. Kilka rzeczy można by tam poprawić (kod mógłby być krótszy), ale nie jest to kluczowe. Ważniejsza była zmiana z 90kB na 8kB. To dobry pomysł i możemy to zrobić... [Czytaj dalej]
Tak, skupiłem się na funkcji, a nie na rozmiarze, ale przyjrzę się jeszcze raz, aby skrócić kod, jeśli funkcja zostanie sprawdzona ;-) . Zwykle używam Linuksa, ale jeśli nie jest to zbyt skomplikowane,... [Czytaj dalej]
Jeśli używasz Linuksa, to może byłbyś w stanie pomóc nam w przeniesieniu: a) tylko autotestów na Linuksa (powinno być bardzo łatwo) b) całego symulatora na Linuksa (powinno być stosunkowo łatwo, ponieważ... [Czytaj dalej]
Chętnie pomogę, ale ostrzegam, że jestem tylko "programistą-hobbystą", a nie poważnym "deweloperem" ;-) . [Czytaj dalej]
Cóż, pierwszą rzeczą byłoby skompilowanie symulatora (lub przynajmniej części autotestów, bez okna SDL) na Linuksie. Jak to zrobić? Win_main.c może być faktycznie skompilowany na Linuksie, jak sądzę. [Czytaj dalej]