HTML5 IndexedDB, Web SQL Database et guerres de navigateur

Je commence le développement d’une application Web avec des exigences de stockage de firebase database hors ligne. Longue histoire courte, l’application devrait pouvoir fonctionner sur:

  • L’un des principaux navigateurs de bureau, Chrome préféré
  • Safari sur iOS
  • Navigateur natif d’Android (basé sur V8 et WebKit)

La question est donc de savoir quelle technologie choisir: IndexedDB ou Web SQL Database?

En ce qui concerne Web SQL Database, d’une part, il est prêt à être utilisé dans l’un des scénarios ci-dessus. D’autre part, Mozilla a déclaré que Firefox ne le mettra jamais en œuvre et que, conformément à la version de travail HTML5, la spécification était dans une impasse:

Cette spécification est dans une impasse: tous les implémenteurs intéressés ont utilisé le même backend SQL (Sqlite), mais plusieurs implémentations indépendantes sont nécessaires pour suivre un chemin de normalisation. Jusqu’à ce qu’un autre implémenteur soit intéressé par l’implémentation de cette spécification, la description du dialecte SQL est restée simplement une référence à Sqlite, ce qui n’est pas acceptable pour un standard. Si vous êtes un développeur intéressé par l’implémentation d’un backend SQL indépendant, veuillez contacter l’éditeur pour qu’il puisse écrire une spécification pour le dialecte, permettant ainsi à cette spécification de progresser.

IndexedDB est l’alternative préconisée par Mozilla, mais elle ne sera disponible que dans Firefox 4. Microsoft est intéressé et Chrome le supportera également. Je ne sais rien des plans d’Apple concernant IndexedDB.

Je suis personnellement enclin à choisir Web SQL Database, mais ce n’est que parce que je suis habitué à SQLite que j’aime la puissance et l’expressivité de SQL et que je comprends le modèle relationnel. IndexedDB, pour moi, est une incertitude.

Cela dit, j’ai peur de parier sur le mauvais cheval. Est-il sûr de supposer que le support de la firebase database Web SQL continuera d’exister, même si IndexedDB devient la norme?

(Une note sur CouchDB: le voyez-vous aussi comme une alternative?)

Étant donné que WebSQL ne prend en charge que les trois exigences répertoriées, votre choix ne devrait-il pas être simple? Vous n’avez aucun aperçu de la feuille de route de développement pour Safari ou Android, utilisez donc ce dont vous disposez.

Eh bien, comme pour tout ce qui concerne l’informatique, le jeu est “abstraction”.

Si vous parvenez à créer une couche adéquate fonctionnant à la fois sur un magasin SQL et un magasin de clés / valeurs, vous êtes idéalement isolé du problème et pouvez prendre en charge l’implémentation appropriée sur un navigateur donné. Si votre modèle de données et vos modèles d’access ne correspondent pas au plus petit dénominateur commun (par exemple, ak / v store), cela résout votre problème.

Si vous pouvez utiliser l’un ou l’autre magasin, travaillez sur une couche d’access décent et abordez le problème dans cette direction.

Attention, ce n’est pas parce que vous avez un magasin ak / v en arrière-plan que vous devez modéliser vos données uniquement avec un modèle ak / v. Essentiellement, tout un DB est sur le backend est ak / v store. Si vous ne possédez pas une quantité folle de données, vous pouvez faire beaucoup de choses. Avec une grande quantité de données, les obstacles que vous pourriez avoir à traverser peuvent vous coûter des performances que vous pourriez ne pas voir avec une plus petite quantité de données. Tout dépend.

Votre firebase database a-t-elle besoin de beaucoup plus que les magasins de clé / valeur? Sinon, j’ai trouvé un certain nombre de paquets javascript pour l’abstraction de firebase database basée sur un navigateur local. Un de ces paquets est jStore:

http://code.google.com/p/jquery-jstore/

Je l’ai récemment utilisé pour append un stockage de clé / valeur locale. Il est bien documenté et le temps d’intégration était négligeable – il prend en charge un ensemble de solutions de stockage, y compris le stockage local flash, via son API.

CouchDB est une excellente solution – pour un problème qui ne correspond pas tout à fait avec le vôtre. Découvrez mobile couchone . Pas uniquement pour les «applications Web», mais peut fournir une firebase database avec laquelle vous pouvez travailler, si vous avez une certaine flexibilité avec la spécification.

Avec l’exigence de Safari sur iOS, il n’y a pas d’autre alternative que WebSQL. WebSQL est pris en charge dans d’autres navigateurs mobiles tels que Opera et Blackberry. Je ne pense pas qu’ils vont supprimer le support WebSQL même s’ils ont IndexedDB. D’une certaine manière, ils sont complémentaires.

D’autre part, sur la guerre de stockage du navigateur, IndexedDB gagne pour de bon. IE et FF auront seulement IndexedDB. Le fait ironique est que FF implémente IndexedDB sur Sqlite.

Ce que je voudrais dire, c’est que IndexedDB est plus qu’un simple magasin de valeur clé. Il a index et transaction. Ces seules deux font presque toutes les fonctionnalités de la requête SQL, y compris la jointure, le conditionnel et le sorting. Ce n’est pas évident au premier abord en raison de son API asynchrone.

Les performances d’IndexedDB sont meilleures que WebSQL. C’est plus sécurisé. Il est plus flexible pour les cas d’utilisation javascript. Enfin, il est plus facile à utiliser.

Pour illustrer ce cas, j’utiliserai le code sudo de ma bibliothèque , mais vous pouvez utiliser directement l’API IndexedDB:

Le magasin ‘people’ contient le champ d’index ‘name’ et le champ indexé ‘hobby’. En JSON,

people = { name: 'Foo Bar', email: '[email protected]' hobby: ['camping', 'swimming']}; 

Récupérer le nom de «personnes» dont le passe-temps est le «camping».

 var req = db.keys('people', 'hobby', IDBKeyRange.only('camping')); req.done(function(campers) { db.keys('people', campers, 'name').done(function(names) { console.log(names); }); }); 

Ce qui est intéressant avec ce code, c’est qu’il n’y a pas de sérialisation impliquée. C’est donc très rapide.

L’exemple suivant illustre une requête de graphique d’amitié. friendship magasin d’objects d’ friendship n’a qu’un seul champ indexé liste d’ friend_list . Il utilise la clé de magasin d’objects people comme clé primaire hors ligne. people magasin d’objects de people a de nombreux atsortingbuts, parmi lesquels le champ de location . La requête est de trouver la liste des amis qui me connaissent et d’ other_guy et situés dans «Singapour».

 var q1 = new ydn.db.Iterator('friendship', 'friend_list', IDBKeyRange.only(me)); var q2 = new dn.db.Iterator('friendship', 'friend_list', IDBKeyRange.only(other_guy)); // if location is not indexed, a filtered value query is used. var q3 = new ydn.db.Iterator('people', new ydn.db.Expression(['"location"', "'Singapore'", '='])); // if location is indexed, an index query is used. // var q3 = new ydn.db.Iterator('people', 'location', IDBKeyRange.only('Singapore')); var current_loop = 2; // start from inner loop var join_algo = function(keys, index_keys) { var advancement = []; advancement[keys.length - 1] = null; var has_adv = false; for (var i = 0; i < keys.length; i++) { if (!goog.isDef(keys[i])) { // completed iterator if (i != 0) { advancement[i] = false; // request to restart the iteration advancement[i - 1] = true; // advance outer iterator current_loop = i - 1; } // i == 0 means we are done. has_adv = true; break; } } if (!has_adv) { // continue looping current advancement[current_loop] = true; } return advancement; } var result = db.scan([q3, q1, q2], join_algo); result.done(function(keys, index_keys, values) { console.log(values); // should get desire list of friends }); 

Encore une fois, cette requête de jointure est juste une parsing de clé et donc très rapide. Par défaut, scan utilise l'algorithme de fusion sortingée pour trouver les clés correspondantes, mais ici, affiche un algorithme de jointure naïve en boucle nestede. La jonction de tables est donc possible, mais vous devez coder l'algorithme de jointure. Mais les algorithmes plus récents comme la fusion en zigzag sont plus rapides que possible avec Sqlite car toutes les entrées sont sortingées, les curseurs peuvent bien progresser et, plus important encore, le processus de jointure peut exploiter des connaissances externes qui ne sont pas dans la firebase database. Avec SQL, l'opération de jointure est opaque.

En dehors de cela, IndexedDB peut utiliser des techniques telles que le streaming et la cartographie / réduction du traitement.

Ma recommandation est de choisir IndexDB , car il existe un IndexDB Polyfill disponible.

Tous les navigateurs prenant en charge WebSQL peuvent prendre en charge l’ API IndexDB de cette manière. L’inverse serait très difficile à implémenter, donc si vous souhaitez atteindre tous les navigateurs connaissant certaines API DB, IndexDB est le meilleur choix aujourd’hui.


Note: Même si cette question est ancienne, elle est toujours pertinente. Je pense donc que les réponses à cette question méritent une mise à jour. Et désolé pour la solution de liaison uniquement, alors j’ai ajouté uniquement des liens vers des destinations généralement durables: W3C et GitHub

Je réponds à cela en 2016 (5 ans après avoir posé cette question) et tout ce qui concerne la dépréciation de WebSQL est toujours valable . IndexedDB, en revanche, bénéficie du support de tous les principaux fournisseurs de navigateurs .

Donc, pour quiconque pourrait se retrouver ici avec la même décision à prendre, optez pour IndexedDB.

Comme le suggèrent d’autres, une telle décision n’est pas nécessairement une décision à prendre; on peut simplement choisir (ou créer) une bibliothèque qui utilise la firebase database disponible sur un ordinateur client.

BakedGoods diffère de ces bibliothèques déjà suggérées ici de plusieurs manières; de manière plus pertinente, elle permet de spécifier explicitement le ou les types de stockage à utiliser, ce qui permet au développeur d’introduire d’autres facteurs (tels que des caractéristiques de performance) dans le processus de prise de décision.

Avec elle, effectuer des opérations de stockage quel que soit le type de firebase database pris en charge est une question de …

… spécifiant les options d’opération appropriées et les configs équivalents pour les deux types de firebase database:

 //If the operation is a set(), and the referenced structures //don't exist, they will be created automatically. var webSQLOptionsObj = { databaseName: "Example_DB", databaseDisplayName: "Example DB", databaseVersion: "", estimatedDatabaseSize: 1024 * 1024, tableData: { name: "Main", keyColumnName: "lastName", columnDefinitions: "(lastName TEXT PRIMARY KEY, firstName TEXT)" }, tableIndexDataArray: [name: "First_Name_Index", columnNames: "(firstName)"] }; var indexedDBOptionsObj = { databaseName: "Example_DB", databaseVersion: 1, objectStoreData: { name: "Main", keyPath: lastName, autoIncrement: false }, objectStoreIndexDataArray: [ {name: "First_Name_Index", keyPath: "firstName", unique: false, multiEntry: false} ], }; var optionsObj = { conductDisjointly: false, webSQL: webSQLOptionsObj, indexedDB: indexedDBOptionsObj }; 

… et mener l’opération:

 bakedGoods.set({ data: [ {value: {lastName: "Obama", firstName: "Barack"}}, {value: {lastName: "Biden", firstName: "Joe"}} ], storageTypes: ["indexedDB", "webSQL"], options: optionsObj, complete: function(byStorageTypeStoredItemRangeDataObj, byStorageTypeErrorObj){} }); 

Son interface simple et sa prise en charge d’installations de stockage inégalées se font au désortingment de certaines configurations spécifiques aux installations de stockage. Par exemple, il ne prend pas en charge la conduction des opérations de stockage dans les tables WebSQL avec des clés primaires multi-colonnes.

Donc, si vous utilisez beaucoup ces types de fonctionnalités, vous voudrez peut-être chercher ailleurs.

Oh, et dans un souci de transparence totale, BakedGoods est maintenu par vos soins :).