Przechowywanie danych obrazu dla aplikacji sieciowej offline (baza danych przechowywania po stronie klienta)

105

Mam aplikację internetową offline korzystającą z buforowania aplikacji. Muszę mu dostarczyć około 10MB - 20MB danych, które zapisze (po stronie klienta) składających się głównie z plików graficznych PNG. Operacja wygląda następująco:

  1. Aplikacja internetowa pobiera i instaluje się w pamięci podręcznej aplikacji (używa manifestu)
  2. Żądania aplikacji internetowej z plików danych PNG serwera (jak? - zobacz alternatywy poniżej)
  3. Czasami aplikacja internetowa ponownie synchronizuje się z serwerem i dokonuje niewielkich częściowych aktualizacji / usuwania / dodawania do bazy danych PNG
  4. FYI: Server to serwer JSON REST, który może umieszczać pliki w wwwroot do odbioru

Oto moja aktualna analiza "baz danych" opartych na kliencie, które obsługują binarny magazyn obiektów blob

ZOBACZ AKTUALIZACJĘ na dole

  • AppCache (poprzez manifest dodaj cały plik PNG, a następnie aktualizuj na żądanie)
    • WAD: każda zmiana elementu bazy danych PNG będzie oznaczać całkowite pobranie wszystkich elementów w manifeście (naprawdę zła wiadomość!)
  • WebStorage
  • PhoneGap i SQLLite
    • CON: Sponsor odrzuci ją jako aplikację natywną wymagającą certyfikacji
  • plik zip
    • Serwer tworzy plik zip, umieszcza go w wwwroot i powiadamia klienta
    • użytkownik musi ręcznie rozpakować pliki (przynajmniej tak to widzę) i zapisać w systemie plików klienta
    • Aplikacja sieci Web używa interfejsu API FileSystem do odwoływania się do plików
    • CON: ZIP może być zbyt duży (zip64?), Długi czas tworzenia
    • CON: Nie jestem pewien, czy FileSystem API może zawsze czytać z piaskownicy (tak mi się wydaje)
  • Karta USB lub SD (powrót do epoki kamienia ...)
    • Przed przejściem w tryb offline użytkownik będzie lokalnie na serwerze
    • Więc moglibyśmy poprosić go o włożenie karty SD, niech serwer zapełni ją plikami PNG
    • Następnie użytkownik podłączy go do laptopa, tabletu
    • Aplikacja internetowa będzie używać interfejsu API FileSystem do odczytywania plików
    • CON: Nie jestem pewien, czy FileSystem API może zawsze czytać z piaskownicy (tak mi się wydaje)
  • WebSQL
    • CON: w3c porzucił to (całkiem źle)
    • Mogę rozważyć opakowanie Javascript, które używa IndexedDB i WebSQL jako rozwiązania awaryjnego
  • FileSystem API
    • Chrome obsługuje odczyt / zapis obiektów blob
    • CON: brak jasności co do IE i FireFox (IE10, ma niestandardowy msSave)
    • caniuse.com zgłasza wsparcie dla IOS i Androida (ale znowu, czy to tylko r / w JSON, czy też zawiera pełny interfejs API obiektu BLOB do pisania?
    • WADA: Ludzie z FireFox nie lubią FileSystem API i nie jest jasne, czy obsługują zapisywanie obiektów blob: https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/
    • PRO: znacznie szybszy niż IndexedDB dla obiektów blob zgodnie z jsperf http://jsperf.com/indexeddb-vs-localstorage/15 (strona 2)
  • IndexedDB
    • Dobra obsługa w IE10, FireFox (zapisywanie, odczytywanie blobów)
    • Dobra szybkość i łatwiejsze zarządzanie niż system plików (usuwanie, aktualizacja)
    • PRO: zobacz testy prędkości: http://jsperf.com/indexeddb-vs-localstorage/15
    • Zobacz ten artykuł na temat przechowywania i wyświetlania obrazów w IndexedDB: https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/
    • CON: Potwierdziłem, że Chrome nie obsługuje jeszcze zapisywania blobów (aktualny błąd, ale nie jest jasne, kiedy zostanie naprawiony)
    • AKTUALIZACJA: programiści Chrome potwierdzają, że pracują nad tym zarówno dla komputerów stacjonarnych, jak i Androida! nie ma jeszcze osi czasu.
  • Opakowanie LawnChair JavaScript http://brian.io/lawnchair/
    • PRO: bardzo czysty wrapper dla IndexedDB, WebSQL lub jakiejkolwiek posiadanej bazy danych (pomyśl o polyfill)
    • CON: nie można przechowywać binarnych obiektów blob, tylko dane: uri (kodowanie base64) (prawdopodobnie fatalna wada ze względu na koszt dekodowania)
  • IndexedDB JQUERY polyFill https://github.com/axemclion/jquery-indexeddb
    • Parashuram napisał ładne opakowanie JQUERY dla surowego interfejsu IndexedDB
    • PRO: znacznie upraszcza korzystanie z IndexedDB, miałem nadzieję dodać podkładkę / polyfill dla Chrome FileSystemAPI
    • CON: Powinien obsłużyć plamy, ale nie udało mi się go uruchomić
  • idb.filesystem.js http://ericbidelman.tumblr.com/post/21649963613/idb-filesystem-js-bringing-the-html5-filesystem-api
    • Eric Bidelman @ Google napisał dobrze przetestowany PolyFill FileSystem API, który używa Indexed DB jako rozwiązania awaryjnego
    • PRO: FileSystem API dobrze nadaje się do przechowywania obiektów blob
    • PRO: działa świetnie w FireFox i Chrome
      • PRO: świetne do synchronizacji z opartą na chmurze CouchDB
    • CON: nie wiadomo dlaczego, ale nie działa na IE10
  • Biblioteka JavaScript PouchDB http://pouchdb.com/
    • świetne do synchronizowania CouchDB z lokalną bazą danych (używa WebSQL lub IndexedDB (choć nie mój problem)
    • WAD: BEZ WAD, PouchDB obsługuje teraz binarne bloby dla wszystkich najnowszych przeglądarek (IE, Chrome, Firefox, Chrome na urządzenia mobilne itp.), A także wielu starszych przeglądarek. Tak nie było, kiedy po raz pierwszy napisałem ten post.

UWAGA: aby zobaczyć dane: kodowanie uri w PNG utworzyłem przykład pod adresem: http://jsbin.com/ivefak/1/edit

Pożądane / przydatne / niepotrzebne funkcje

  • Brak aplikacji natywnej (EXE, PhoneGap, ObjectiveC itp.) Na kliencie (czysta aplikacja internetowa)
  • Wystarczy działać na najnowszym Chrome, FireFox, IE10 dla laptopów
  • Bardzo chcę tego samego rozwiązania dla tabletu z Androidem (IOS też byłby fajny), ale do działania potrzebna jest tylko jedna przeglądarka (FF, Chrome itp.)
  • Szybka początkowa populacja DB
  • WYMAGANIE: Bardzo szybkie pobieranie obrazów przez aplikację internetową z magazynu (baza danych, plik)
  • Nie jest przeznaczony dla konsumentów. Możemy ograniczyć przeglądarki i poprosić użytkownika o wykonanie specjalnych ustawień i zadań, ale zminimalizujmy to

Implementacje IndexedDB

  • Jest doskonały artykuł o tym, jak IE, FF i Chrome wewnętrznie implementują to pod adresem : http://www.aaron-powell.com/web/indexeddb-storage
  • W skrócie:
    • IE używa tego samego formatu bazy danych co Exchange i Active Directory dla IndexedDB
    • Firefox używa SQLite, więc w pewnym sensie implementuje bazę danych NoSQL w bazie danych SQL
    • Chrome (i WebKit) używają magazynu klucza / wartości, który ma dziedzictwo w BigTable

Moje aktualne wyniki

  • Zdecydowałem się użyć podejścia IndexedDB (i polyfill z FileSystemAPI for Chrome, dopóki nie dostarczą obsługi BLOB)
  • Przy pobieraniu płytek miałem dylemat, ponieważ ludzie z JQUERY zastanawiają się, czy dodać to do AJAX
  • Wybrałem XHR2-Lib Phila Parsonsa, który jest bardzo podobny do JQUERY .ajax () https://github.com/pmp/xhr2-lib
  • Wydajność dla 100 MB pobrań (IE10 4s, Chrome 6s, FireFox 7s).
  • Nie mogłem zmusić żadnego z opakowań IndexedDB do pracy z obiektami blob (lawnchair, PouchDB, jquery-indexeddb itp.)
  • Zwinąłem własne opakowanie, a wydajność to (IE10 2s, Chrome 3s, FireFox 10s)
  • Zakładam, że w przypadku FF widzimy problem z wydajnością korzystania z relacyjnej bazy danych (sqllite) dla magazynu innego niż sql
  • UWAGA: Chrome ma doskonałe narzędzia do debugowania (karta programisty, zasoby) do sprawdzania stanu IndexedDB.

KOŃCOWE Wyniki zamieszczone poniżej jako odpowiedź

Aktualizacja

PouchDB obsługuje teraz binarne obiekty blob dla wszystkich najnowszych przeglądarek (IE, Chrome, Firefox, Chrome na urządzenia mobilne itp.), A także wielu starszych przeglądarek. Tak nie było, kiedy po raz pierwszy napisałem ten post.

Dr.YSG
źródło
1
webstorage nie obsługuje json, ale ciągi znaków, więc możesz kodować base64 swoje imagez i wyświetlać je z powrotem jako dataurls.
mpm
Ok, ale prawdopodobnie nie optymalne (lub w ramach limitu) dla 20 MB zdjęć, które w rzeczywistości są śliskimi kafelkami mapy, które muszą być szybko pobierane i wyświetlane przez aplikację mapową LEAFLET podczas powiększania i przesuwania.
Dr ISG
Badania, które przeprowadziłeś, są bardzo pomocne.
Bogdan Kulynych
Chodzi mi o to, że nie musisz zajmować się binarnymi plamami, jeśli używasz obrazów png.
mpm
Masz rację, czy nie miałbyś nic przeciwko, jeśli zaktualizuję dokument, aby odzwierciedlić Twoje uwagi?
Dr.YSG

Odpowiedzi:

25

Wyniki Pamięć podręczna obiektów blob offline dla śliskich map PNG

Testowanie

  • 171 plików PNG (łącznie 3,2 MB)
  • Testowane platformy: Chrome v24, FireFox 18, IE 10
  • Powinien również działać z Chrome i FF na Androida

Pobierz z serwera WWW

  • przy użyciu XHR2 (obsługiwanego w prawie wszystkich przeglądarkach) do pobierania obiektów blob z serwera internetowego
  • Poszedłem z XHR2-Lib Phila Parsonsa, który jest bardzo podobny do JQUERY .ajax ()

Przechowywanie

Pokaz

  • Używam Leaflet http://leafletjs.com/, aby wyświetlić kafelki mapy
  • Użyłem funkcjonalnej wtyczki warstwy kafelków autorstwa Ishmaela Smyrnow do pobrania warstwy kafelków z bazy danych
  • Porównałem warstwę kafelków opartą na DB z czysto lokalną pamięcią (localhost: //)
  • Nie ma zauważalnej różnicy w wydajności! między użyciem IndexedDB a plikami lokalnymi!

Wyniki

  • Chrome: pobieranie (6,551 s), zapisz (8,247 s), całkowity czas, który upłynął: (13,714 s)
  • FireFox: pobieranie (0,422 s), zapisz (31,519 s), całkowity czas, który upłynął: (32,836 s)
  • IE 10: pobieranie (0,668 s), przechowywanie: (0,896 s), całkowity czas, który upłynął: (3,758 s)
Dr.YSG
źródło
4

Dla twoich wymagań sugeruję, że opracowanie nowego polyfill opartego na dwóch innych: FileSystem API to IndexedDB i IndexedDB to WebSQL - jest najlepszą opcją.

Pierwsza z nich umożliwi obsługę przechowywania blobów w Chrome (FileSystem API) i Firefox (IndexedDB), druga zaś powinna zapewniać obsługę Androida i iOS ( WebSQL ). Potrzebne jest tylko sprawienie, aby te polyfills działały razem i przypuszczam, że nie jest to trudne.

Uwaga: ponieważ nie mogłem znaleźć żadnych informacji na ten temat w sieci, powinieneś sprawdzić, czy przechowywanie obiektów blob przy użyciu wypełnienia WebSQL będzie działać na iOS i Androidzie. Wygląda jednak na to, że powinno działać:

var sql = ["CREATE TABLE", idbModules.util.quote(storeName), "(key BLOB", createOptions.autoIncrement ? ", inc INTEGER PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY", ", value BLOB)"].join(" ")

Źródło

Bogdan Kulynych
źródło
Skłaniam się ku twojej sugestii, ale czekam na wiadomość od innych. Nie mam poręcznego androida, ale dobrze byłoby stworzyć jsBin lub jsFiddle i zobaczyć, co działa na Androidzie.
Dr ISG
1
Te dwie krople są różne. Sqlite blob jest buforowaniem tablicy w javascript, podczas gdy js blob nie ma odpowiednika w sqlite. Obiekt BLOB nie może konwertować na bufor tablicy, chociaż można go sklonować strukturalnie.
Kyaw Tun
2

Mam przykłady buforowania map (otwarty przykład, odkryj regiony i powiększenia, przełącz się w tryb offline, a odkryte regiony będą dostępne).

Istnieją map.js- warstwa mapy dla kafelków offline, storage.js- implementacja pamięci masowej oparta na IndexedDb i WebSQL (ale to tylko testowa implementacja ze słabą wydajnością).

  • W przypadku plików witryn (html, css, js itp.) Wolę używać pamięci podręcznej aplikacji.
  • Do przechowywania wolę używać Indexed DB (obsługa blobów), Web SQL (tylko base64), FileWriter (obsługa blobów, ale tylko chrome). Szczerze mówiąc, przechowywanie to duży problem. Potrzebujesz najszybszego rozwiązania o kluczowej wartości, które połączy je wszystkie. Myślę, że skorzystanie z istniejącego rozwiązania jest dobrą decyzją.
  • Do pobierania użyłem płótna z CORSem. Ale myślę o WebWorkers i XHR2 i to może być lepsze niż płótno, ponieważ płótno ma pewne problemy z CORS w różnych przeglądarkach i innych (na przykład ten tytuł był źle przechowywany w operze ).

Dodatkowe informacje o rozmiarach dla 2 miliardów miasta ( Mińsk ):

  • Zoom - 9, kafelki - 2, rozmiar - 52 kb, poprzedni - 52 kb;
  • Zoom - 10, kafelki - 3, rozmiar - 72 kb, poprzedni - 124 kb;
  • Zoom - 11, kafelki - 7, rozmiar - 204 kb, poprzednie - 328 kb;
  • Zoom - 12, kafelki - 17, rozmiar - 348 kb, poprzednie - 676 ​​kb;
  • Zoom - 13, kafelki - 48, rozmiar - 820 kb, poprzedni - 1,5 mb;
  • Zoom - 14, płytki - 158, format - 2,2 mb, poprzedni - 3,7 mb;
  • Zoom - 15, kafle - 586, wielkość - 5,5 mb, poprzednia - 9,3 mb;
  • Zoom - 16, kafle - 2264, format - 15 mb, poprzedni - 24,3 mb;
tbicr
źródło
Zakładam, że są to płytki JPG w śliskim formacie EGPS3857, prawda? ponieważ używam ulotki i robię rastrowe owele, musiałem iść z PNG. sprawdź również moje demo korzystania z PouchDB (który używa IDB poniżej). stackoverflow.com/questions/16721312/…
Dr.YSG
O tak, buforujesz w locie, ale czy wiesz, gdzie mogę się udać, aby pobrać wstępnie zbudowaną mapę OSM (na całym świecie), aby powiększyć 10, 11 lub 12? Zatrzymalibyśmy to na naszym serwerze offline.
Dr ISG
Nie, używane PNGz domyślną projekcją (EGPS: 3857), ale bez względu na to JPEGlub PNGdlatego, że jest używane przez imgtag lub canvas. W moim przykładzie możesz po prostu wstępnie załadować kafelki, jeśli znasz klucze kafelków ( storage.add('x_y_z', 'data:image/png;base64,...')dla każdego przechowywanego kafelka), ale zawsze możesz je uzyskać, jeśli znasz tylko granice (wielokąt) i powiększenia.
tbicr
Chcę się upewnić, że nie mamy problemu z językiem. Czy jest jakieś miejsce, w którym możemy dostać ogólnoświatowy zestaw śliskich płytek OSM (PNG lub JPG) do poziomu powiększenia 10?
Dr ISG
Możesz pobrać formularz kafelków tile.osm.org(mapnik renderer). Na przykład http://tile.openstreetmap.org/10/590/329.png( zoom/ x/ y.png). Te kafelki mają Access-Control-Allow-Origin: *nagłówek, więc możesz je pobrać przez Ajax lub pobrać dane uri (base64) przez płótno. Już można pobrać płytek pomocą swojego konta manifest.json {id: 0-0-0}, ale należy upewnić się, że mają rację zoom, x, ysekwencję.
tbicr
1

Kilka lat temu (nie dokładnie w epoce kamienia łupanego) korzystałem z podpisanego apletu java, który wysyłał zapytania do serwera o synchronizację / aktualizację wymagań, pobierał odpowiednie pliki z serwera i zapisywał je w systemie plików użytkownika (nie w bazie danych). To rozwiązanie może zadziałać, chociaż będziesz potrzebować kogoś, kto napisze aplet i podpisze go. W przypadku rozwiązań bazodanowych taki aplet może używać jdbc dostępnego dla większości baz danych przy użyciu localhost na odpowiednim porcie (np. 3306 dla MySQL). Uważam, że tag apletu jest przestarzały w języku Html5, ale nadal działa. Brak doświadczenia na tabletach z Androidem, więc nie mogę komentować tej części.

Manidip Sengupta
źródło
1
Zacząłem programować w FORTRANIE w 1968 roku używając dziurkacza. Tak więc rozwiązania z epoki kamienia nie są dla mnie nowością.
Dr ISG