ill
...
|
Hallo. Ich hab hier ein Problem mit der Performance der JS-Engine von Internet Explorer 7. Ich habe ein Array mit ca. 300 - 350 verschiedenen Einträgen. In manchen Columns liegen Strings, die mit IDs gefüllt sind und sich mit den Einträgen in anderen überschneiden : Eintrag 1: "101;102;103;104;" Eintrag 2: "101;103;106;" etc. Nun möchte ich aus allen Einträgen im Array, nachdem eine Filterung passiert ist, alle übergebliebenen IDs einmalig in einem Array abgespeichert haben. Mittels diesen werden dann Filterkategorien ein- oder ausgeblendet. Für DOM-Manipulation kommt jQuery 1.6 zum Einsatz. Hab mir hier kurz etwas gebastelt, bin mir aber ziemlich sicher, dass diese Lösung in Hinsicht auf Performance noch einiges zu wünschen übrig lässt: var _uniques = documentFinder.datTable.fnGetFilteredData();
var lists = $('#tableHead .itunes .list-holder ul');
var ct = 1;
var uCol = [];
while(ct <= 4){
var uniqueCol = "";
var li= ct-1;
var x=0;
for(x; x <_uniques.length; x=x+1){
if(ct===1){
uniqueCol += (_uniques[x][ct])+";";
}else{
uniqueCol += (_uniques[x][ct]);
}
}
uCol[li] = uniqueCol.split(";");
uCol[li] = uCol[li].unique();
uCol[li].pop();
var itemCt = 0;
lists.eq(li).find('li').each(function(){
var reqtitle = "";
if(itemCt != 0){
if(ct===1){
reqtitle = $(this).find("a").text();
}else{
reqtitle = $(this).attr("itemid");
}
var hide = true;
if($.inArray(reqtitle, uCol[li]) >= 0){
hide = false;
}
if (!hide) {
$(this).show();
} else {
$(this).hide();
}
}
itemCt++;
});
ct++;
}
Array.prototype.unique = function () {
var o = {},
i, l = this.length,
r = [];
for (i = 0; i < l; i += 1) o[this[i]] = this[i];
for (i in o) r.push(o[i]);
return r;
};
Eventuell kennt ja jemand einen guten Weg, so etwas performant hinzubekommen, damit man sich das ganze auch in etwas betagteren Browser ansehen kann, ohne selbst alt dabei zu werden. tia
|
watchout
Legendundead
|
Deine Lösung lässt vor allem Dokumentation zu wünschen übrig.
Würd mal sagen dass du bessere Performance haben wirst wenn du mit dem Object aus "Array.prototype.unique" weiter arbeitest statt mit einem Array. Wegen "32: [...] $.inArray(...)" Object-Properties sind in ner HashMap gespeichert, dadurch haben die konstante Laufzeit beim Zugriff, inArray sucht dir im Schnitt jedes mal das halbe Array durch, egal wie gut die Suche is.
Dein zweites Problem dürfte (je nach Dokumentgröße) die Zeile sein: 22: lists.eq(li).find('li').each(...) da weiss ich aber im Moment keine Lösung
|
DirtyHarry
aka robobimbo
|
|
watchout
Legendundead
|
|
ill
...
|
so, sorry, hatte wahnsinnig viele andere Dinge um die Ohren die letzten Tage, danke schon mal für die Antworten. Habe die ganze Funktion noch mal umgekrempelt, weil ich pro Kategorie-Liste einmal über das ganze Daten-Array iteriert habe. Sorry für die miese Kommentierung des ganzen, habe versucht die wichtigsten Schritte nun ein bisschen zu erklären. filtering: function (c, sStr) {
var searchString = "";
//Filter DataTable
//First col -> plain string
if(c === 1){
documentFinder.datTable.fnFilter(sStr, 1, true, true, true);
//Additional cols -> regex
}else{
searchString = documentFinder.selectedCols[0]+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2];
documentFinder.datTable.fnFilter(searchString, 5, true, true, true);
}
//Get filtered data-Array
var _uniques = documentFinder.datTable.fnGetFilteredData();
//Get DOM-Elements of sorting-lists
var lists = $('#tableHead .itunes .list-holder ul');
//Declaration of data-arrays
var sysFHT = [];
var bwHT = [];
var btHT = [];
var anfHT = [];
var cohHT = [];
var uniqueCol = [];
uniqueCol[0] = "";uniqueCol[1] = "";uniqueCol[2] = "";uniqueCol[3] = "";uniqueCol[4] = "";
//Add all data-strings together in specific uniqueCol-Array
var x, max;
for(x=0,max=_uniques.length; x < max; x+=1){
var y;
for(y=1; y<6; y+=1){
if(y===1){
uniqueCol[y-1] += _uniques[x][y] + ";"; //Add ; to end of first-col data for splitting
}
else{
uniqueCol[y-1] += _uniques[x][y];
}
}
}
//Create string that holds all unique coherency-strings for regex-search
var ustr = uniqueCol[4].split(";");
cohHT = ustr.unique();
cohHT.pop();
var strstr = cohHT.join("");
//Iterate over all ul-sorting columns
var z;
for(z=0;z<4;z+=1){
var clmStr = uniqueCol[z].split(";");
var uCol = [];
//adding column-specific data to uCol
if(z===0){
sysFHT = clmStr.hash();
uCol = sysFHT;
}else if(z===1){
bwHT = clmStr.hash();
uCol = bwHT;
}else if(z===2){
btHT = clmStr.hash();
uCol = btHT;
}else if(z===3){
anfHT = clmStr.hash();
uCol = anfHT;
}
if(z!==4){
var itemCt = 0;
//Iterate over all li-elements
lists.eq(z).find('li').each(function(){
var reqtitle = "", nsStr= "";
if(itemCt != 0){
//get filtering data
if(z===0){
reqtitle = $(this).find("a").text(); //string for col 1
}else{
reqtitle = $(this).attr("itemid"); //given id for other columns
//Build column-specific regex
if(z===1){
nsStr = reqtitle+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2];
}else if(z===2){
nsStr = documentFinder.selectedCols[0]+"_"+reqtitle+"_"+documentFinder.selectedCols[2];
}else if(z===3){
nsStr = documentFinder.selectedCols[0]+"_"+documentFinder.selectedCols[1]+"_"+reqtitle;
}
}
//see if searchItem still exists in filtered data as plain string
if((reqtitle in uCol) === false){
$(this).addClass("hidden");
}else{
//see if searchItem exists in any coherency in the product-list
if(z!==0){
var found=false;
if(strstr.search(nsStr) != -1){
found = true;
}
if(!found){
$(this).addClass("hidden");
}else{
$(this).removeClass("hidden");
}
}else{
$(this).removeClass("hidden");
}
}
}
itemCt++;
});
}
}
};
//Returns Object : unique values as keys
Array.prototype.hash = function () {
var o = {},
i, l = this.length,
r = [];
for (i = 0; i < l; i += 1) o[this[i]] = null;
return o;
};
//Returns Array: unique data in value
Array.prototype.unique = function () {
var o = {},
i, l = this.length,
r = [];
for (i = 0; i < l; i += 1) o[this[i]] = null;
for (i in o) r.push(i);
return r;
};
Größtes Problem das ich habe: Um die ganzen unique values aus den Daten zu bekommen, füge ich zuerst alle Strings einer bestimmten "Column" von allen Datensätzen zusammen, splitte diese dann auf und kann aus dem resultierenden Array die unique einträge bestimmen. Da die Strings sehr, sehr lang werden können, halte ich selbst nicht ziemlich viel von dieser Lösung, mir will aber nichts einfallen, womit ich das besser hinbekommen. watchout, du hast sicherlich recht mit der Schleife über die li-Elemente, doch auch hier fällt mir keine andere Lösung ein, da ich die Daten eines jeden einzelnen li-Elements im Hinblick auf die gesamten gefilterten Daten überprüfen muss. Hat da irgendjemand eine Idee? edit: Grundsätzlich sei dazu gesagt: In modernen Browsern performt das ganze (no na ned) perfekt, im IE7 bin ich derzeit auf ca. 2-3 Sekunden Response-Time herunten, was mir hinsichtlich Usability jedoch noch nicht gefällt, weiters scheint es mit page-reload langsamer zu werden, keine Ahnung warum. Wie sieht es eigentlich mit Garbage Collection aus? Würde es etwas bringen, nach dem Funktionsdurchlauf alle Objekte/Arrays auf null zu setzen?
Bearbeitet von ill am 22.06.2011, 11:08
|
watchout
Legendundead
|
//Build column-specific regex
if(z===1){
nsStr = reqtitle+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2];
}else if(z===2){
nsStr = documentFinder.selectedCols[0]+"_"+reqtitle+"_"+documentFinder.selectedCols[2];
}else if(z===3){
nsStr = documentFinder.selectedCols[0]+"_"+documentFinder.selectedCols[1]+"_"+reqtitle;
}
Bin grad nicht sicher ob ich was überseh, aber könnte man das nicht ausserhalb der .each(...) funktion auch machen? Was du willst is ja diese Funktion so klein wie möglich zu bekommen
|
watchout
Legendundead
|
Weisst was, poste mal Beispieldaten, und beschreibe nochmal was du erreichen willst anhand der Beispieldaten, ich glaub dass du zu kompliziert denkst
|
ill
...
|
Der reqtitle ändert sich ja mit jedem einzelnen List-Element. In diesem Code-Segment wird für jedes noch nicht gefilterte li-Element eine Regex-Suche zusammengestellt, die überprüft, ob dieses eine List-Element noch in irgendeiner vorhandenen Zusammenhängigkeit vorkommt. Daten sehen folgendermaßen aus: ["Testdata", "TestCategory", "100;101;102;103;", "1001;1002;1003;1004;1006;1007;", "10001;10002;10003;10004;10005;",
"100_1001_10001;101_1001_10002;102_1001_10003;103_1001_10004;102_1002_10001;104_1003_10004;101_1003_10005;102_1001_10002;102_1004_10001;103_1003_10005;101_1005_10005;103_1005_10002;102_1006_10005;101_1007_10002;103_1007_10001;101_1008_10005;101_1009_10002;102_1010_10001;103_1009_10005;101_1007_10002;103_1009_10001;",
"", ""]
String 1: Produktname String 2: Produktkategorie/Produktfamilie String 3, 4 und 5: Verschiedene Kategorien, in denen dieses Produkt zum Einsatz kommt String 6: Verfügbare Zusammenhängigkeiten unter diesen Kategorien Nun wird im Script nach einer Datenfilterung geprüft, ob eine Kategorie überhaupt noch irgendwo in den gefilterten Daten vorkommt. Wenn nicht -> hide. Danach wird bei den noch vorhandenen mittels regex auf alle zusammengefassten Zusammenhängigkeiten überprüft, ob die Kategorie in Hinsicht auf andere ausgewählte Filterkategorien (die werden über documentFinder.selectedCols ausgelesen) noch relevant ist. Sollte sie nicht in einer verfügbaren Zusammenhängigkeit aufscheinen -> hide
|
watchout
Legendundead
|
Ich meinte DOM-Code
|
ill
...
|
Die Auswahllisten sind im Grunde nichts besonderes, so sehen sie aus nachdem sie von JavaScript befüllt worden sind <div class="itunes">
<div class="list-holder">
<ul>
<li itemid="1" class="active"><a href="#">Alle</a></li>
<li itemid="2"><a href="#">Test 1</a></li>
<li itemid="3"><a href="#">Test 2</a></li>
<li itemid="4"><a href="#">Test 3</a></li>
<li itemid="5"><a href="#">Test 4</a></li>
<li itemid="6"><a href="#">Test 5</a></li>
<div class="list-holder">
<ul>
<li itemid="100" class="active"><a href="#">Alle</a></li>
<li itemid="101"><a href="#">Test 1</a></li>
<li itemid="102"><a href="#">Test 2</a></li>
<li itemid="103"><a href="#">Test 3</a></li>
<li itemid="104"><a href="#">Test 4</a></li>
<li itemid="105"><a href="#">Test 5</a></li>
</ul>
</div>
<div class="list-holder">
<ul>
<li itemid="1000" class="active"><a href="#">Alle</a></li>
<li itemid="1001"><a href="#">Test 1</a></li>
<li itemid="1002"><a href="#">Test 2</a></li>
<li itemid="1003"><a href="#">Test 3</a></li>
<li itemid="1004"><a href="#">Test 4</a></li>
<li itemid="1005"><a href="#">Test 5</a></li>
</ul>
</div>
<div class="list-holder">
<ul>
<li itemid="10000" class="active"><a href="#">Alle</a></li>
<li itemid="10001"><a href="#">Test 1</a></li>
<li itemid="10003"><a href="#">Test 2</a></li>
<li itemid="10004"><a href="#">Test 3</a></li>
<li itemid="10005"><a href="#">Test 4</a></li>
<li itemid="10006"><a href="#">Test 5</a></li>
</ul>
</div>
</div>
|
ill
...
|
So, hab die Funktion jetzt nochmal umgekrempelt, um weniger Schleifendurchläufe und String-Operationen drin zu haben. Funktioniert mit 300 Einträgen einigermaßen zufriedenstellend, 600 dauern dann schon etwas länger, ist aber noch im Bereich des ertragbaren (ich verlang ja von meiner 55 PS - Schüssel auch nicht, dass sie 250 fährt) filtering: function (c, sStr) {
var searchString = "";
//Filter DataTable
//First col -> plain string
if(c === 1){
documentFinder.datTable.fnFilter(sStr, 1, true, true, true);
//Additional cols -> regex
}else{
searchString = documentFinder.selectedCols[0]+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2]+";";
documentFinder.datTable.fnFilter(searchString, 2, true, true, true);
}
//Get filtered data-Array
var _uniques = documentFinder.datTable.fnGetFilteredData();
//Declaration of data-arrays
var sysFHT = [], cohHT = [], uniqueCol = [];
uniqueCol[0] = "";uniqueCol[1] = "";
//Add all data-strings together in specific uniqueCol-Array
var x, max, y;
for(x=0,max=_uniques.length; x < max; x+=1){
uniqueCol[0] += _uniques[x][1] + ";";
uniqueCol[1] += _uniques[x][2];
}
//Create string that holds all unique coherency-strings for regex-search
var ustr = uniqueCol[1].split(";");
cohHT = ustr.unique();
cohHT.pop();
var strstr = cohHT.join(";");
strstr += ";"
//Iterate over all ul-sorting columns
var z;
for(z=0;z<4;z+=1){
//adding column-specific data to uCol
if(z===0){
var clmStr = uniqueCol[0].split(";");
sysFHT = clmStr.hash();
}
var itemCt = 0;
//Iterate over all li-elements
documentFinder.lists.eq(z).find('li').each(function(){
var reqtitle = "", nsStr= "";
if(itemCt !== 0){
//get filtering data
if(z===0){
reqtitle = $(this).find("a").text(); //string for col 1
}else{
reqtitle = $(this).attr("itemid"); //given id for other columns
//Build column-specific regex
switch(z){
case 1: nsStr = reqtitle+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2]+";"; break;
case 2: nsStr = documentFinder.selectedCols[0]+"_"+reqtitle+"_"+documentFinder.selectedCols[2]+";"; break;
case 3: nsStr = documentFinder.selectedCols[0]+"_"+documentFinder.selectedCols[1]+"_"+reqtitle+";"; break;
}
}
if(z!==0){
var found=false;
//see if searchItem exists in any coherency in the product-list
if(strstr.search(nsStr) !== -1){
found = true;
}
if(!found){
$(this).addClass("hidden");
}else{
$(this).removeClass("hidden");
}
}else{
//see if searchItem still exists in filtered data as plain string
if((reqtitle in sysFHT) === false){
$(this).addClass("hidden");
}else{
$(this).removeClass("hidden");
}
}
}
itemCt++;
});
}
$('#tableHead .itunes .list-holder').jScrollPane();
sysFHT = null; cohHT = null; uniqueCol = null;
}
Interessant wär jetzt noch, wieso die Funktion nach Page-Reload fast doppelt so langsam läuft. Kann das wirklich am Script liegen oder ist da die Maschine, auf der mein nativer IE 7 läuft, etwa schuld daran? Nach IE 7 - Restart läufts wieder wie gehabt...
|
watchout
Legendundead
|
(Zeile 31)
var ustr = uniqueCol[1].split(";");
cohHT = ustr.unique();
cohHT.pop();
var strstr = cohHT.join(";");
strstr += ";"
[...]
(Zeile 69)
if(strstr.search(nsStr) !== -1){
found = true;
}
Warum? (Zeile 31)
var ustr = uniqueCol[1].split(";");
var ustr_last = ustr.pop();
cohHT = ustr.hash();
cohHT[ustr_last] = null;
var strstr = cohHT.join(";");
strstr += ";"
[...]
(Zeile 69)
if(strstr[nsStr]){
found = true;
}
Geht das nicht auch so? Hashtables, use them!
|
ill
...
|
Naja, das Problem ist, dass die Variable "nsStr" eine regex-Abfrage gespeichert hat, da wird mit Zugriff per Key etwas schwierig, weshalb ich auch die .search() - Methode verwende
|
watchout
Legendundead
|
nsStr = reqtitle+"_"+documentFinder.selectedCols[1]+"_"+documentFinder.selectedCols[2]+";"
was is hier regex?
|
ill
...
|
ist ne äußerst einfache. Teilweise stehen halt dann strings wie 101_...._.....; drin
|