Forums : Xul, Xbl, JS...

Aller à la discussion :  Plus récente Plus ancienne

Aller à la page :  1 2 3

# Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 15:19

Bonjour, mon programme est un visualiseur de base de données SQLite3. Au démarrage, je charge les informations contenues dans ma base de données, ce sont des infos sur des cartes à jouer telles que : Nom, description, code, rareté,... rien de bien extraordinaire.

  • 1er point :

Pour l'instant, j'ai quasiment tout codé et ma base contenait 17 cartes (juste pour vérifier la validité de mon code) et mon logiciel s'ouvrait instantanément, mais je me suis dit qu'à terme, le chargement devrait être plus long car il y a environ 3000 cartes dans le jeu.

Je me suis donc lancé dans dans une petite progressbar qui augmente au fur et à mesure que je charge mes données dans un tableau, et ça marche, enfin presque...

En effet, j'ai gonflé artificiellement ma base de données avec un script automatique pour rentrer 400 cartes... et maintenant quand je lance mon programme, il est beaucoup plus long au démarrage, rien ne s'affiche, puis paf, toute mon interface s'affiche, ma progressbar est déjà remplie et tout marche. Pas cool... l'intérêt d'une progressbar est de faire patienter durant le chargement, et là, ma fenêtre ne s'affiche pas avant chargement totale de mes données, c'est donc râté.

Comment faire pour afficher ma fenêtre puis charger mes données ensuite afin de voir ce chargement dans ma progressbar ? Voici une version allégé de mon code :

var cards = new Array();
window.onload = function()
{
  cards = getAllCards();
}

Et dans getAllCards() j'ai une boucle qui remplie mon tableau et en même temps incrémente ma progressbar.

  • 2° point :

Je voudrais inclure un Splash screen à mon application mais lorsque je fais un window.open dans mon "onload" et bien mon splash screen s'affiche après ma fenêtre de base, ce n'est donc plus un splash screen... comment résoudre ce problème ?

  • 3° point :

Avec seulement 17 cartes, mon logiciel prenait 14,5 Mo de RAM... Avec 400 cartes, il passe à 38,8 Mo !!! Et je trouve ça énorme car à terme, il y aura environ 3000 cartes ! un rapide calcul me fait penser que la mémoire pourrait alors monter à 240 Mo !!! o.O . En fait je charge mes cartes dans un tableau afin d'y avoir rapidement accès pour mes filtres en temps réel... mais je ne pensais pas que ça prendrait tant de mémoire que ça... Est-ce moi qui ne sait pas coder ? Dois-je détruire mes variables désuètes ? Dois-je utiliser un autre procédé ? Bref, je ne sais pas trop quoi faire...

J'espère que quelqu'un pourra quand même me venir en aide, merci d'avance =)

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : thefab

Date : 02/02/2007 15:45

  1. J'ai essayé un peu la même chose pour mon SQLite Manager. Avoir une progressbar durant l'exécution de la requête, mais comme toi impossible de mettre à jour l'UI depuis le code qui accède à SQLite !
  2. Inverser l'ordre des fenêtres ? Faire de ton splash screen la première fenêtre avec tout le code de chargement des données et un fois que tout est chargé, hop affichage de la deuxième fenêtre (la principale en fait)
  3. Est-ce que tu as vraiment besoin des 3000 cartes en même temps en mémoire ? Sinon charges uniquement celles dont tu as besoin au moment voulu

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : chBok

Date : 02/02/2007 16:10

1. Ce problème de rafraichissement de l'UI pendant un long script me semble avoir déjà été abordé. Ne fallait-il pas se servir de setTimeout() artificiels pour y parvenir ?

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 17:48

thefab > Concernant mes 3000 cartes, je les mets en mémoire car je voulais avant tout une interface réactive durant le filtre de mes cartes en temps réel, et je pensais que le meilleur moyen était de tout mettre en mémoire et de parcourir tout mon tableau à chaque modif. de mon filtre en application mes condition IF, afin d'afficher ou non la carte... Je pensais que ce serait le mieux... Mais pensez-vous qu'il serait préférable d'utiliser à chaque fois une requête SQL plutôt ?

chBok > J'avais déjà lu ce genre de problème mais je n'avais pas percuté que ça touchait ma situation... Effectivement, il faudrait donc une "astuce" pour parvenir à ce résultat apparemment.

Je vais essayer différentes techniques pour voir ce que ça donne et je vous tiens au courant.

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : teddyber

Date : 02/02/2007 17:54

pour ton histoire de filtres et la question de savoir s'il est pertinent de charger les cartes en mémoire, voici mon cas : je développe une appli qui propose une textbox qui à chaque input fait une requète à une base SQLite. la requète+le vidage du tree qui affiche+le remplissage du tree est quasi-instantané (j'ai aujourd'hui 300 élements dans la base)

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 18:10

Bah ce que tu fais, c'est donc exactement l'alternative de ce que je fais ! Et tu me dis donc que c'est instantané pour 300 éléments ? Utilises-tu "createElement" aussi pour ton tree ?

Il faudrait peut-être donc que j'essaie de changer mon fusil d'épaule et miser sur la rapidité de la requête SQLite plutôt que le parcours de mon tableau mis en mémoire tu penses ?

PS : Je viens de tenter un setTimeout qui "résoud" 1 problème : maintenant, l'interface s'affiche bien... mais bizarrement, ma progressbar passe directement à 100 % et j'ai du mal à croire que ce soit parce que c'est instantanné puisque ça met un peu de temps. Pourtant je devrais le voir se remplir, voici mon code :

function getAllCards()
{
var Nb_Cards_loaded = 0;
var data = ycd.get("...REQUETE SQL...")
while (data.executeStep()) {
  results.push("...MES DONNEES...")
  Nb_Cards_loaded++;
  $("loaderbar").value = Math.round(Nb_Cards_loaded*100/Nb_Cards);
  }
}

Et ce code fonctionne bien puisqu'en mettant un alert() dans ma boucle pour faire afficher le %... ben j'ai bien le bon chiffre et en plus ma progressbar se met correctement à jour dans mon interface.

C'est bizarre non ? Il n'est pas pas question de requête SQL à interrompre non ? C'est juste une boucle... Comment ça se fait que la boucle tourne sans même avoir le temps de mettre à jour ma Progressbar ?

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : teddyber

Date : 02/02/2007 18:16

euh oui j'use (et j'abuse) de createElement, de setAttribute et autres appendChild

en tout cas ce qui prends du temps chez moi c'est clairement la manipulation du DOM et pas la requète à SQLite (mesuré à coup de console.time et console.timeEnd dans firebug)

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 18:30

Tiens mais alors ce que tu me dis est très étrange ! Je viens de tester un truc : J'ai désactivé mon système de filtre... en gros, tous mes IF et mes condition pour ne garder que :

  • Requête SQL qui remplie un tableau
  • Affichage sans condition de tous les éléments (400) dans mon listbox avec du createElement et du appendChild.

Et bien : AUCUN CHANGEMENT ! La vitesse est la-même ! Et quand je rafraichis ( = Je vide mon listbox pour le reremplir avec les mêmes éléments) et bien je ne vois aucune différence ce qui veut dire que le vidage/peuplage est INSTANTANE !

Mais alors ça voudrait dire que c'est ma requête qui bouffe tout ce temps ! o.O

Il lui faut environ 3/4 seconde pour charger mes données, c'est-à-dire 400 éléments. __Est-ce que ce sont mes réglages SQLite3 qui seraient mauvais ? J'utilise Xulrunner 1.9a1... et j'ai un PIV 2.4 + 1 Go de RAM sous Ubuntu Edgy Eft.

Il me semble avoir lu sur ce forum un paramétrage à faire et qui change tout : genre de 10 sec à 1 sec ! Je vais rechercher ce topic...

Voici la requête et mon remplissage de tableau si ça peut aider quelqu'un à comprendre pour cela prend tant de temps :

var data = ycd.get("SELECT Card_ID, ID_Card, Group_ID, cards.Name as Name, Description, cards.Reference as Reference, Level, Atk, Def, Code,  Monster_Attribute_ID, Monster_Type_ID, Monster_Subtype_ID, Type_ID, cards.Extension_ID as Extension_ID, Country_ID, Language_ID, Model_ID, extensions.Name as Extension_Name, extensions.Reference as Extension_Ref, Release_Date FROM cards LEFT JOIN extensions USING(Extension_ID) ORDER BY cards.Reference ASC");
while (data.executeStep()) {
  results.push({"Card_ID" : data.getInt32(0),
					"ID_Card" : data.getInt32(1),
					"Group_ID" : data.getInt32(2),
					"Restricts" : getRestricts(data.getInt32(2),data.getInt32(14)),
					"Reference" : data.getString(5),
					"Name" : {"Source": data.getString(3),
								"Locale": getTranslation('local_cards','Name','ID_Card',data.getInt32(1),UserLanguageID)},
					"Extension" : {"ID": data.getInt32(14),
									"Country_ID": data.getInt32(15),
									"Language_ID": data.getInt32(16),
									"Model_ID": data.getInt32(17),
									"Name": data.getString(18),
									"Reference": data.getString(19),
									"Released": data.getString(20)},
					"Type" : getCardType(data.getInt32(13),data.getInt32(16)),
					"Subtype" : {"ID": data.getInt32(13),
									"Name": getTranslation('types','Name','Type_ID',data.getInt32(13),data.getInt32(16)),
									"Locale": getTranslation('types','Name','Type_ID',data.getInt32(13),UserLanguageID)},
					"Monster_Attribute" : {"ID": data.getInt32(10),
											"Name": getTranslation('monster_attributes','Name','Monster_Attribute_ID',data.getInt32(10),data.getInt32(16)),
											"Locale": getTranslation('monster_attributes','Name','Monster_Attribute_ID',data.getInt32(10),UserLanguageID)},
					"Monster_Type" : {"ID": data.getInt32(11),
										"Name": getTranslation('monster_types','Name','Monster_Type_ID',data.getInt32(11),data.getInt32(16)),
										"Locale": getTranslation('monster_types','Name','Monster_Type_ID',data.getInt32(11),UserLanguageID)},
					"Monster_Subtype" : {"ID": data.getInt32(12),
											"Name": getTranslation('monster_subtypes','Name','Monster_Subtype_ID',data.getInt32(12),data.getInt32(16)),
											"Locale": getTranslation('monster_subtypes','Name','Monster_Subtype_ID',data.getInt32(12),UserLanguageID)},
					"Monster_Effects" : getCardMonsterEffects(data.getInt32(1),data.getInt32(16)),
					"Level" : data.getInt32(6),
					"Atk" : data.getInt32(7),
					"Def" : data.getInt32(8),
					"Description" : {"Source": data.getString(4),
										"Locale": getTranslation('local_cards','Description','ID_Card',data.getInt32(1),UserLanguageID)},
					"Code" : data.getString(9),
					"Rarities" : getCardRarities(data.getInt32(0),data.getInt32(16)),
					"Rulings" : getCardRulings(data.getInt32(1),data.getInt32(16))});
}

Merci encore pour votre aide =)

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : hhf

Date : 02/02/2007 21:19

qui dit beaucoup de datas dit RDF et tree, ya pas d'autre solution.

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 21:38

Ah ouais ? J'sais pas... RDF c'est du XML à la base non ? Et l'accès XML pour des bases de données très relationnelles, me semble que c'est pas vraiment adapté ni facile d'utilisation non ? Et pour les performances, suis pas sûr que ça soit au top non ?

SQLite3 a quand même été retenu par Mozilla pour sa légèreté et sa puissance, travailler avec du RDF ce serait pas s'entêter dans quelque chose qui va finir par devenir obsolète ?

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : hhf

Date : 02/02/2007 22:59

ben oui, mais pour le peuplement d'element graphic, rien ne vaut un rdf. Soit plus precis sur la structure des datas que tu veux afficher. J'ai lu en diagonnale ton truc, et si j'ai bien compris, tu remplis une listbox, en utilisant le DOM, c'est ca qui est lent. Avec RDF, et un tree et le flags="dont-build-content", non seulement se sera asynchrone, mais en plus tu pourras trier les données affichées. Et je te garanti que se sera rapide, et pas de freez ecran

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 02/02/2007 23:24

Ah oui ? J'sais pas... pourtant ça me parait pas si lent que ça l'affichage (vidage+remplissage de 400 éléments instantané). D'après ce que je vois, pour l'instant c'est surtout ma requête qui est lente.

Tu penses donc que je devrais faire quelque chose du genre :

  • A la première ouverture, à partir de ma BDD SQLite3 je génère des RDF contenant les données à afficher dans mes différents listbox, en faisant toutes mes requêtes et mes jointures pour avoir toutes mes infos selon l'affichage que je souhaite.
  • Ensuite je me sers à chaque fois de ces RDF afin d'utiliser des templates et des rules, c'est ça ? C'est plus rapide ça ? Mais est-ce que le fichier ne sera pas énorme ? Environs 3000 enregistrements assez gros car reliés à plusieurs tables.

C'est que mes données sont quand même très complexes... Toutes mes tables sont liées à au moins 2/3 autres tables pour une internationalisation de toutes les propriétés, etc... Et si je me fais ça par RDF, il va clairement y avoir des données générées en double non ?

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : hhf

Date : 03/02/2007 01:25

Mhm, il faudrait en dire plus, nb de tables, cardinalitées, vues que tu veux afficher, etc. Peut etre que ta requete n'est pas judicieuse, une mauvaise jointure et c'est un bon produit matriciel....

Ce que je comprend pas, c'est la vues (les données à l'ecran que tu veux avoir), pourkoi tu veux garder les relation entre elle ?

Si j'ai bien compris, c'est des card style "Magic the gathering" dont tu veux faire un interface pour consulté une BDD contenant toutes les infos de ces dernieres. Donc (tu me corrige) tu veux un tree avec toutes cards, peut etre arborescent pour ranger les cards par sous categories. Puis au click sur une cards, tu affiches un certain nombre d'infos s'y raportant. Peut etre aussi de koi mettre à jour les relations

Si c'est ca que tu veux, je vois pas ou tu veux gerer tes jointures sur l'ihm. Ou alors j'ai pas trop compris ce que tu m'a dis.

Je suis à l'ecoute...

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : Raphael

Date : 03/02/2007 08:28

Oui, tu as compris, c'est exactement ça mon programme, et ça marche au poil pour une vingtaine de cartes... Mais déjà à 400, ça commence à mettre du temps au chargement sans que je puisse mettre de progressbar (1er pb) et ça prend pas mal de RAM (40Mo... 2° pb). Alors je n'ose imaginer quand j'en aurai 3000... =/

Voici le schéma de la base de données : http://www.ycd-project.org/portail/img/y(..)

En fait, à l'ouverture, je remplie un tableau cards dans lequel je mets toutes les infos de chaque carte (cf. mon post plus haut où j'ai mis la structure de mon tableau) : nom, traductions, propriétés et toutes les traductions locales... et ce afin de pouvoir filtrer rapidement mes cartes en temps réel. Je fais appel à de nombreuses fonctions pour aller chercher les bonnes infos de suite, ainsi j'y ai accès facilement par la suite dans mon tableau.

J'avais 2 optiques possibles :

  • Soit je mets toutes les infos en mémoire et du coup, pour filtrer je n'ai plus qu'à parcourir mon tableau pour afficher ou non chaque carte (c'est ce que je fais actuellement).
  • Soit je ne charge rien au début, mais à chaque modification du filtre, je fais une requête SQL pour renvoyer les résultats et les afficher dans mon listbox.

J'ai préféré la 1ère solution en me disant qu'à choisir entre :

  • Ouverture lente + Réactivité au top ensuite
  • Ouverture rapide + Filtrage un peu lent (car, pour moi, je pensais que parcourir un tableau en mémoire était plus rapide que de faire des requêtes SQLite).

Bah, j'ai pensé que c'était mieux une ouverture lente + utilisation/réactivité/filtrage rapide...

Voilà donc la situation. Qu'en penses-tu ?

EDIT : Je suis en train de redécouvrir mes topics d'il y a 5 mois et où je demandais des avis de connaisseurs sur la manière d'aborder mon problème : http://xulfr.org/forums/read.php?1,6223,(..)

Je me posais la question : SQLite3 ou RDF ? Et voici les avis de l'époque :

  • thefab :

Je voulais plutôt parler de temps de construction que de temps d'accès en fait, le moteur DOM est rapide et afficher en construisant les éléments prend peu de temps. C'est dans ce sens la que je te disais de tester tes requête avec SQLite Manager car les éléments XUL sont générés. L'inverse serait, comme le dit Laurent, de travailler avec des templates, mais en local je te conseille SQLite3 pour stocker tes données et surtout pas RDF qui est absolument inutilisable pour stocker des milliers d'enregistrements.

  • Laurent :

L'utilisation de mozstorage peut être envisagé. Mais aussi rdf pourquoi pas ! Tout dépend du volume de donnée etc..
Par exemple, tu peux peut-être envisager de stocker en rdf toutes les valeurs de références (categories par exemple...), cela permettra d'utiliser les templates.
Je ne suis pas d'accord avec thefab sur le fait que rdf n'est pas fait pour stocker des milliers de données. En tout cas, à l'affichage, avec les templates, ce sera beaucoup plus rapide que si tu extrait toi même tes données de sqlite et tu génères des élements via le dom. Aprés, derrière, si tu fais beaucoup de manipulation de données compliquées, c'est vrai que l'api rdf n'est pas aisée. Mais cela peut être caché par une API de plus haut niveau (que tu realiserais)

Sachant que je ne modifie pas les données de ma Base de Données (3000 enregistrements !)... et que je n'aspire qu'à une seule chose : Une interface la plus réactive possible et un filtrage par :

  • données numériques ( <=, =, >=)
  • données textes : Pouvoir retrouver un bout de texte dans une variable donnée.

Quelle serait la meilleure méthode ?

  • Requête SQL à chaque changement d'état ? (listbox géré manuellement : Vidage/remplissage)
  • Parcours d'une tableau allégé (3000 entrées quand même) ne contenant que les infos nécessaires au filtrage ? (listbox géré manuellement : Vidage/remplissage)
  • Utilisation de RDF et de Template ? (mais mon fichier RDF ne serait-il pas un peu gros pour 3000 enregistrements ? Serait-il mis dans la RAM ?)

Merci d'avance pour vos conseils expérimentés à tous...

# Re: Comment charger mes données après mon interface ? PB de Progressbar...

Envoyé par : hhf

Date : 03/02/2007 16:53

Bon en effet ton modele n'est pas des plus simple, (pour un truc perso) au taf on a des truc qui rentre sur plusieurs page A3 LOL. J'aurais preferé un MCD avec les cardinalitées plutot que les foreign key. ca aurait été plus simple à analyser. Néanmoins, je persite à dire que RDF est une meilleur solution et surtout n'utilise pas une listbox, mais un tree, bien plus performant avec bcp de données. Mais ceci dit ca ne te supprime pas ta BDD, il faut je pense, faire un truc comme ca.

au chargement de l'appli tu fais une req SQL pour avoir toutes les cards, tu mets en forme en RDF et tu appliques au tree des cards, sur la selection d'un treeitem, tu recup l'ID de la cards et tu fais une requete SQL pour avoir les infos supplementaires. etc ... etc.. Pour le tri, tu utilise les fonction de tree de l'arbre, qd au filtre, tu refait une requete et tu repeuple.

Tu peux faire un essais, tu fait un fichier RDF à plat, avec tes 3000 entrees, puis tu l'affecte à un tree, tu verras le tps et la reactivitée. De plus avec ce system, tu poura faire ton appli en remote XUL ou pas.

PS, il me semble dans ton modele que monster_types et monster_subtypes pourait etre regroupé en une seule table. A voir

Aller à la page :  1 2 3

Il n'est plus possible de poster des messages dans ce forum.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.