Design-Änderung innerhalb zwischen Funktionsaufrufen
romero
- javascript
Hallo liebe Gemeinde,
ich komme wieder zu euch, weil ich eine Problemlösung brauche.
Es geht dadrum, ich möchte das Design meines Scriptes nach dem Aufrufen der einzelnen Funktionen. Sprich: ich möchte eine Art "Fortschrittsbalken" erstellen, um dem User zu zeigen, wie lange das Script noch braucht bis er "fertig" mit dem Erstellen bestimmter Listen ist.
Und zwar sieht die bisherige Hauptfunktion wie folgt aus:
function init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime )
{
//--------------------------------//
//-- Aufruf der Unterfunktionen --//
//--------------------------------//
infile_Aircabin = Excel_Tabelle_Laden( locations.infile, locations.startSheet );
anzahl_Aircabin = infile_Aircabin;
infile_Aircabin = Leere_Eintraege_Loeschen( infile_Aircabin );
anzahl_Aircabin = Leere_Eintraege_Loeschen( anzahl_Aircabin );
infile_Aircabin = Daten_konvertieren( infile_Aircabin );
anzahl_Aircabin = Anzahl_konvertieren( anzahl_Aircabin );
list_Aircabin = Sortierte_Liste( [ locations.posA, locations.posB, locations.posC, locations.posD, locations.posE ] )[0];
infile_unique_Aircabin = MattenUnikate( infile_Aircabin, infile_zusatz_tmp );
anzahl_Aircabin = MattenUnikateAnzahl( infile_Aircabin, infile_unique_Aircabin, anzahl_Aircabin );
excel_infile_Aircabin = MattenUnikate( infile_Aircabin );
infile_unique_Aircabin = infile_unique_Aircabin.concat( infile_zusatz_tmp );
anzahl_Aircabin = anzahl_Aircabin.concat( infile_zusatz_anzahl_tmp );
infile_unique_gesamt_Aircabin = MattenUnikate_Gesamt( infile_unique_Aircabin );
anzahl_gesamt_Aircabin = MattenUnikateAnzahl_Gesamt( infile_unique_Aircabin, infile_unique_gesamt_Aircabin, anzahl_Aircabin );
...
return;
};
Nun will ich aber folgende Funktion hinzufügen:
(Diese würde ich nach jeder Funktion aufrufen wollen)
//----------------------------------------------------//
//-- Anzeigestatus für den Fortschritt des Scriptes --//
//----------------------------------------------------//
function Fortschritt_Anzeige( Anzeigewert )
{
var Wert = Anzeigewert + 5;
document.getElementById( "STL_Fortschritt_Anzeige" ).style.display = "inline";
document.getElementById( "STL_Fortschritt_Anzeigestatus" ).innerHTML = Wert;
return Wert;
};
Also nach jedem Aufruf der o.g. Funktionen den Prozentwert um 5 erhöhen und gleichzeitig ausgeben. Und genau da zeigt er es nicht an.
Das Script läuft alle Funktionen durch ohne das Design zu verändern. Erst am Ende wird es ausgegeben bzw. ist die Veränderung sichtbar, aber nur der letzte Wert.
Wie also bewerkstellige ich es, dass er mir eine Art "Ladezustand" übermittelt? Oder anders gefragt: Wie halte ich das Script kurz an, damit er die "Veränderung" anzeigt? Mittels setTimeout() oder gibt es da andere Möglichkeiten dazu?
PS: ich will nicht auf die Eingabe des Users warten (war schonmal ein Thema von mir), sondern das Ändern des Design's nach jeder Funktion.
LG Romero
Hallo,
ich möchte eine Art "Fortschrittsbalken" erstellen, um dem User zu zeigen, wie lange das Script noch braucht bis er "fertig" mit dem Erstellen bestimmter Listen ist.
Wie lange läuft das Script und warum braucht es so lange? Sind das etwa synchrone Input/Output-Operationen?
Also nach jedem Aufruf der o.g. Funktionen den Prozentwert um 5 erhöhen und gleichzeitig ausgeben. Und genau da zeigt er es nicht an.
Das Script läuft alle Funktionen durch ohne das Design zu verändern. Erst am Ende wird es ausgegeben bzw. ist die Veränderung sichtbar, aber nur der letzte Wert.
Ja, das ist normal. Der Browser setzt eine Änderung am DOM erst durch Layouting und Painting um, wenn der aktuelle Call-Stack abgearbeitet ist und der JavaScript-Interpreter zur Ruhe kommt bzw. mit dem nächsten geplanten Funktionaufruf weitermacht. Stichwort »JavaScript Event Loop«. Sprich: Dein JavaScript muss zur Ruhe kommen.
Wie also bewerkstellige ich es, dass er mir eine Art "Ladezustand" übermittelt? Oder anders gefragt: Wie halte ich das Script kurz an, damit er die "Veränderung" anzeigt? Mittels setTimeout() oder gibt es da andere Möglichkeiten dazu?
Ja, setTimeout bzw. setImmediate ist eine Möglichkeit. Eine andere ist das Erzwingen des Renderings durch die Abfrage von offsetWidth oder einer anderen Eigenschaft, dessen Wert der Browser erst durch Layouting korrekt zurückliefern kann.
PS: ich will nicht auf die Eingabe des Users warten (war schonmal ein Thema von mir), sondern das Ändern des Design's nach jeder Funktion.
Das Problem ist letztlich dasselbe wie bisher. :) Wenn du zwischen JavaScript-Operationen etwas ausgeben willst, muss du dein JavaScript in kleine Teile aufsplitten, die asynchron aufgerufen werden können, sodass der aktuelle Call-Stack abgearbeitet wird, damit der Browser den Zwischenstand rendert.
Das lässt sich z.B. mithilfe einer Queue lösen, die abgearbeitet wird:
var one = function () {…};
var two = function () {…};
var three = function () {…};
var renderStatus = function () {…};
var queue = [one, two, three];
var loop = function () {
var func = queue.shift();
if (func) {
func(); // Führe Schritt aus
renderStatus(); // Erstatte Bericht
setTimeout(loop, 1); // Beende Call-Stack, erzeuge neuen
// Jetzt kann der Browser rendern
}
};
loop();
Mathias
Vielen Dank Mathias, für deine Antworten. Versuche diese mal zu beantworten:
Wie lange läuft das Script und warum braucht es so lange? Sind das etwa synchrone Input/Output-Operationen?
Nun ja, das Script dient zur Erzeugung von Stücklisten, sprich, aus einer sehr sehr großen Anzahl an Dateien (Teilen) soll anhand einer ausgelesenen Excel-Liste eine *.txt erstellt werden, wo nur ausgewählte Teile vorhanden sind. Und je nachdem wie groß der Ordner ist (kann auch nicht verkleinert werden durch Unterordner) oder wie "aktuell" die Daten sein müssen, kann es halt länger dauern. U.u. an die 1-2 Minuten
Ja, das ist normal. Der Browser setzt eine Änderung am DOM erst durch Layouting und Painting um, wenn der aktuelle Call-Stack abgearbeitet ist und der JavaScript-Interpreter zur Ruhe kommt bzw. mit dem nächsten geplanten Funktionaufruf weitermacht. Stichwort »JavaScript Event Loop«. Sprich: Dein JavaScript muss zur Ruhe kommen.
Ja, setTimeout bzw. setImmediate ist eine Möglichkeit. Eine andere ist das Erzwingen des Renderings durch die Abfrage von offsetWidth oder einer anderen Eigenschaft, dessen Wert der Browser erst durch Layouting korrekt zurückliefern kann.
Das heißt also, ich muss in dem Script Pausen erzwingen, so dass das Script, wie du sagst, zur Ruhe kommt und Zeit bekommt, die Änderungen im Design vorzunehmen.
Nun aber die Frage dazu: Welche Funktionen müsste ich mittels settimeout() starten lassen? Meine Fortschritt_Anzeige() (oder in deinem Falle renderStatus()) oder die anderen Funktionen (one, two, three, ...)?
Das settimeout() dient doch nur dazu, eine Funktion nach einer gewissen Zeit starten zu lassen, aber in der Zeit wird doch keine "Pause" verursacht um das Script design-mäßig zu verändern oder?
Das lässt sich z.B. mithilfe einer Queue lösen, die abgearbeitet wird:
var one = function () {…};
var two = function () {…};
var three = function () {…};
var renderStatus = function () {…};var queue = [one, two, three];
var loop = function () {
var func = queue.shift();
if (func) {
func(); // Führe Schritt aus
renderStatus(); // Erstatte Bericht
setTimeout(loop, 1); // Beende Call-Stack, erzeuge neuen
// Jetzt kann der Browser rendern
}
};
loop();
Ok, also müsste ich meine ganzen Funktionen in diese loop() packen, was aussehen würde wie:
~~~javascript
function init()
{
var one = function Excel_Tabelle_Laden( Wert1 ) {…};
var two = function Leere_Eintraege_Loeschen( Wert1 ) {…};
var three = function Daten_konvertieren( Wert1 ) {…};
var renderStatus = function Fortschritt_Anzeige( Parameter1 ) {…};
//--> Und wie bekomm ich aus den oben genannten Funktionen meine Werte zurück?
//--> Weil vorher hatte ich es wie folgt:
// infile = function Excel_Tabelle_Laden( Ausgangswerte )
// infile = function Leere_Eintraege_Loeschen( infile )
// infile = function Daten_konvertieren( infile )
// ...
//--> also die zurückgegebenen Werte wurden für die weiteren Funktionen benutzt
var queue = [one, two, three];
var loop = function () {
var func = queue.shift();
if (func) {
func(); // Führe Schritt aus
renderStatus(); // Erstatte Bericht
setTimeout(loop, 1); // Beende Call-Stack, erzeuge neuen
// Jetzt kann der Browser rendern
}
};
loop();
};
Und der untere Teil bewirkt, dass er z.B. mir die Excel-Tabelle ausliest,nach dem Beenden in die Fortschritt_Anzeige() springt und da das Design ändert und danach,nach 1ms den "alten" Aufruf beendet und nen neuen aufruft? Hoffe ich hab es so richtig verstanden :)
LG Romero
Ja, das ist normal. Der Browser setzt eine Änderung am DOM erst durch Layouting und Painting um, wenn der aktuelle Call-Stack abgearbeitet ist und der JavaScript-Interpreter zur Ruhe kommt bzw. mit dem nächsten geplanten Funktionaufruf weitermacht. Stichwort »JavaScript Event Loop«. Sprich: Dein JavaScript muss zur Ruhe kommen.
Ja, setTimeout bzw. setImmediate ist eine Möglichkeit. Eine andere ist das Erzwingen des Renderings durch die Abfrage von offsetWidth oder einer anderen Eigenschaft, dessen Wert der Browser erst durch Layouting korrekt zurückliefern kann.
Das heißt also, ich muss in dem Script Pausen erzwingen, so dass das Script, wie du sagst, zur Ruhe kommt und Zeit bekommt, die Änderungen im Design vorzunehmen.
Nun aber die Frage dazu: Welche Funktionen müsste ich mittels settimeout() starten lassen? Meine Fortschritt_Anzeige() (oder in deinem Falle renderStatus()) oder die anderen Funktionen (one, two, three, ...)?
Das ist glaube ich dein 3. Thread mit ähnlichem Inhalt?! Das warst doch du, oder?
Du musst das einmal wirklich verstehen! Dann ist es ganz logisch/leicht.
Das Script muss zur Ruhe kommen ist vielleicht etwas missverständlich. Der Browser muß neu zeichnen/rendern. Das macht er aber nicht wenn gerade ein JS abgearbeitet wird.
Also musst du dein Script abschließen, den Browser rendern lassen und dann ein neues Stück JS starten.
Das musst du aber ja sowieso schon machen, da ein JS welches 1-2 Minuten läuft dich ständig daran erinnert, das es so nicht sein sollte!
Also musst du dein lang laufendes JS in mehrere kurze Teile aufteilen, die zwischendurch den Browser mal wieder was anderes machen lassen. Am Ende eines solchen Teils, kannst du deinen Fortschrittsbalken aktualisieren.
Das settimeout() dient doch nur dazu, eine Funktion nach einer gewissen Zeit starten zu lassen,
Genau!
aber in der Zeit wird doch keine "Pause" verursacht um das Script design-mäßig zu verändern oder?
In der Zwischenzeit zeichnet der Browser deine im Script vorgenommenen Änderungen am DOM auf den Bildschirm, nimmt Maus- und Tastaturevents entgegen und und und.
Das ist glaube ich dein 3. Thread mit ähnlichem Inhalt?! Das warst doch du, oder?
Ja das war ich, glaube ich zumindest :)
Du musst das einmal wirklich verstehen! Dann ist es ganz logisch/leicht.
Ich denke jedesmal dass das was "Neues" für mich und deshalb komme ich ja hierher :/
Das Script muss zur Ruhe kommen ist vielleicht etwas missverständlich. Der Browser muß neu zeichnen/rendern. Das macht er aber nicht wenn gerade ein JS abgearbeitet wird.
Also musst du dein Script abschließen, den Browser rendern lassen und dann ein neues Stück JS starten.
Das musst du aber ja sowieso schon machen, da ein JS welches 1-2 Minuten läuft dich ständig daran erinnert, das es so nicht sein sollte!
Also musst du dein lang laufendes JS in mehrere kurze Teile aufteilen, die zwischendurch den Browser mal wieder was anderes machen lassen. Am Ende eines solchen Teils, kannst du deinen Fortschrittsbalken aktualisieren.
Also mein Gerüst sieht in etwa so aus:
function init()
{
var a = Funktion a( mit Werten );
var b = Funktion b( mit Werten aus a );
var c = Funktion c( mit Werten aus b );
var d = Funktion d( mit Werten aus c);
...
};
D.h. also, erst nachdem das Script diese Init() abgearbeitet hat, kommt er zu Ruhe? Und erst danach wird gerendert?
Jetzt frage ich mal ganz blöd für mich. Wo teile ich da das Script? Bzw. wie schließe ich das oben genannte Gerüst ab? Und wie starte ich da weitere Funktionen?
Vielleicht so?
function init()
{
var a = Funktion a( mit Werten );
};
Start der Fortschritt_Anzeige();
var b = Funktion b( mit Werten aus a );
Start der Fortschritt_Anzeige();
var c = Funktion c( mit Werten aus b );
Start der Fortschritt_Anzeige();
var d = Funktion d( mit Werten aus c);
...
Alle Variablen sind natürlich globale Variablen die eindeutig am jeweiligem Namen zu erkennen sind (in meinem Script).
Und dass das Script 1-2 Minuten läuft, kommt daher, dass die Datenmenge einfach riesig ist, die er erstmal auslesen müsste. In der Regel sind es aber ca. 10-40 Sekunden.
LG Romero
D.h. also, erst nachdem das Script diese Init() abgearbeitet hat, kommt er zu Ruhe? Und erst danach wird gerendert?
Ja, es sei denn nach Init werden noch weitere Funktionen abgearbeitet, dann erst wieder nach diesen. Also zwischen 2 Events oder 2 Timeouts.
Jetzt frage ich mal ganz blöd für mich. Wo teile ich da das Script? Bzw. wie schließe ich das oben genannte Gerüst ab? Und wie starte ich da weitere Funktionen?
Das mußt du entscheiden. Das hängt von der Laufzeit der Funktionen ab.
Vielleicht so?
Mit jeder Funktion für sich kann man anfangen. Eigentlich musst du sicherstellen, das ein Teilstück nie länger als n Sekunden läuft, egal wieviel Daten vorhanden sind. n = 1 dürfte da schon die Obergrenze sein, eher weniger.
Alle Variablen sind natürlich globale Variablen die eindeutig am jeweiligem Namen zu erkennen sind (in meinem Script).
Das ist natürlich die schlechteste Variante. (Da solltest du nochmal drüber nachdenken!)
Und dass das Script 1-2 Minuten läuft, kommt daher, dass die Datenmenge einfach riesig ist, die er erstmal auslesen müsste. In der Regel sind es aber ca. 10-40 Sekunden.
Das macht keinen Unterschied, außerdem musst du auch den Worst Case beherschen.
Ja, es sei denn nach Init werden noch weitere Funktionen abgearbeitet, dann erst wieder nach diesen. Also zwischen 2 Events oder 2 Timeouts.
Nein alle Funktionen sind in diesem init() vorhanden. In diesem wird (bzw. sollte) alles aufgerufen, was benötigt wird.
Jetzt frage ich mal ganz blöd für mich. Wo teile ich da das Script? Bzw. wie schließe ich das oben genannte Gerüst ab? Und wie starte ich da weitere Funktionen?
Das mußt du entscheiden. Das hängt von der Laufzeit der Funktionen ab.
Ich wollte nach jeder aufgerufenen Funktion den Status für den Nutzer ausgeben, also:
Excel-Tabelle ausgelesen: 10%
usw.
Unabhängig von der Laufzeit, wo ist das Script denn fertig abgearbeitet? Nach der letzten (bzw. in der letzten) Funktion in der init()? Oder nach jeder einzelnen Funktion?
Also müsste ich die init() mit einer Funktion starten lassen und alle anderen ausserhalb der init() plazieren?
Sorry das ich jetzt so daher komme, aber will ja verstehen wie du es meinst mit dem abarbeiten einer Funktion, wenn aber alles aus einer großen init()-Funktion kommt.
Mit jeder Funktion für sich kann man anfangen. Eigentlich musst du sicherstellen, das ein Teilstück nie länger als n Sekunden läuft, egal wieviel Daten vorhanden sind. n = 1 dürfte da schon die Obergrenze sein, eher weniger.
Und dass das Script 1-2 Minuten läuft, kommt daher, dass die Datenmenge einfach riesig ist, die er erstmal auslesen müsste. In der Regel sind es aber ca. 10-40 Sekunden.
Das macht keinen Unterschied, außerdem musst du auch den Worst Case beherschen.
Was genau meinst du mit worst case? Nicht das ich nicht weiß was das ist, sondern wie genau du dass jetzt meinst? Wenn die Datenmenge zu groß wird?
Und wie soll ich da das Auslesen der Daten bewerkstelligen? In Teilschritten? Also immer 10 Daten auslesen, speichern, nächsten 10 auslesen,speichern, usw. und am Ende alle Teile zusammenführen? Das kommt noch bzw. ist in Arbeit. Werde diese Datenmenge als "Index'e" in eine *.txt speichern, da kommen nur die Daten rein, welche wirklich wichtig sind. Dadurch wurde die Zeit auf 1/4 verringert.
LG Romero
Ich wollte nach jeder aufgerufenen Funktion den Status für den Nutzer ausgeben, also:
Excel-Tabelle ausgelesen: 10%
usw.
Und dann der Rest Zeitverzögert aufrufen(mit setTimeout).
Unabhängig von der Laufzeit,
Das ist die Frage. vielleicht musst du die einzelnen Funktionen auch nochmal teilen oder nur Teile einer Schleife abarbeiten, um in nächsten Aufruf den nächsten Teil der Schleife zu bearbeiten.
wo ist das Script denn fertig abgearbeitet? Nach der letzten (bzw. in der letzten) Funktion in der init()? Oder nach jeder einzelnen Funktion?
Aller globaler Code der ins Html über script eingebunden wird, wird beim parsen der Seite jeweils volständig abgearbeitet.
Dann kommen eigentlich nur noch einzelne Funktionen die als Eventhandler registriert sind oder per Timeout gestartet werden beim entsprechenden Ereigniss an die Reihe und werden auch wieder vollständig abgearbeitet.
Dazwischen kann der Browser zeichnen.
Also müsste ich die init() mit einer Funktion starten lassen und alle anderen ausserhalb der init() plazieren?
Alle anderen per Timeout.
Sorry das ich jetzt so daher komme, aber will ja verstehen wie du es meinst mit dem abarbeiten einer Funktion, wenn aber alles aus einer großen init()-Funktion kommt.
Kein Problem! Die große init()-Funktion darf es nicht mehr geben, die muß das Ganze nur starten. Dann viele kleine Schritte per Timeout.
Was genau meinst du mit worst case? Nicht das ich nicht weiß was das ist, sondern wie genau du dass jetzt meinst? Wenn die Datenmenge zu groß wird?
Ja.
Und wie soll ich da das Auslesen der Daten bewerkstelligen? In Teilschritten? Also immer 10 Daten auslesen, speichern, nächsten 10 auslesen,speichern, usw. und am Ende alle Teile zusammenführen?
Genau.
Also müsste ich die init() mit einer Funktion starten lassen und alle anderen ausserhalb der init() plazieren?
Alle anderen per Timeout.Sorry das ich jetzt so daher komme, aber will ja verstehen wie du es meinst mit dem abarbeiten einer Funktion, wenn aber alles aus einer großen init()-Funktion kommt.
Kein Problem! Die große init()-Funktion darf es nicht mehr geben, die muß das Ganze nur starten. Dann viele kleine Schritte per Timeout.
So nun die Frage an dich, wie mache ich das :) ?
Ich meine, die function init() lasse ich aus dem Hauptscript starten, eine Art Maske, wo ich ja eine Vorauswahl treffe um die jeweilige init() aufzurufen.
Also so wie ich es verstanden habe, wird weiterhin die init() aus dem Hauptscript gestartet, damit diese *.js-Datei überhaupt ersteinmal geöffnet bzw. gestartet wird.
Und unter dieser init()-Funktion setze ich nun mittels Timeout die einzelnen Funktionen, egal ob ich sie "ausgelagert" habe oder nicht.
Würde dann so aussehen:
function init()
{
//--> leer, dient nur zum starten???
};
var a = excel_tab_laden( Werte );
var renderStatus = Status_anzeigen( Parameter );
var b = Daten_konvertieren( a );
var renderStatus = Status_anzeigen( Parameter );
var c = Daten_auslesen_vergleichen( b );
var renderStatus = Status_anzeigen( Parameter );
...
Die genannten Funktionen sind ausgelagert, damit ich alles nicht mehrmals schreiben muss.
Funktioniert das dann so, wie ich es am oben genannten Gerüst gezeigt hab oder gibt es da noch Sachen, welche ich beachten müsste?
LG Romero
So nun die Frage an dich, wie mache ich das :) ?
Das hatte wir in dem alten Thread schon. Hier mal als Objekt. Wenn du xxx () erst mal weglässt, werden Funktionen nacheinander aufgerufen. Zwischenwerte kannst du am Objekt speichern.
Die Funktion xxx wird hierbei nochmal in viele Teilaufrufe zerlegt, die die Schleifen für i und j immer nur um jeweils eine Schritt abarbeiten.
function MyObj() {
}
MyObj.prototype = {
states: ["uninitialized", "init", "xxx", "yyy"],
actState: 0,
indexI: 0,
indexJ: 0,
SearchValue: 60000,
nextState: function() {
if (this.actState < this.states.length - 1) {
setTimeout(this[this.states[++this.actState]].bind(this));
}
},
init: function() {
// irgendwas kurzes machen
// ...
this.nextState();
},
xxx: function() {
for(var i = this.indexI; i <= 65535;) {
for(var j = this.indexJ; j <= 65535;) {
for(var k = 0; k <= this.SearchValue; ++k) {
if (i==k && j==k && k==this.SearchValue)
{
this.nextState();
return;
}
}
++this.indexJ;
setTimeout(this[this.states[this.actState]].bind(this));
return;
}
++this.indexI;
setTimeout(this[this.states[this.actState]].bind(this));
return;
}
},
yyy: function() {
// irgendwas kurzes machen
// ...
alert("durch");
this.nextState();
},
};
var xxx = new MyObj();
xxx.init();
So nun die Frage an dich, wie mache ich das :) ?
Das hatte wir in dem alten Thread schon. Hier mal als Objekt. Wenn du xxx () erst mal weglässt, werden Funktionen nacheinander aufgerufen. Zwischenwerte kannst du am Objekt speichern.
Die Funktion xxx wird hierbei nochmal in viele Teilaufrufe zerlegt, die die Schleifen für i und j immer nur um jeweils eine Schritt abarbeiten.function MyObj() {
}
MyObj.prototype = {
states: ["uninitialized", "init", "xxx", "yyy"],
actState: 0,
indexI: 0,
indexJ: 0,
SearchValue: 60000,
nextState: function() {
if (this.actState < this.states.length - 1) {
setTimeout(this[this.states[++this.actState]].bind(this));
}
},
init: function() {
// irgendwas kurzes machen
// ...
this.nextState();
},
xxx: function() {
for(var i = this.indexI; i <= 65535;) {
for(var j = this.indexJ; j <= 65535;) {
for(var k = 0; k <= this.SearchValue; ++k) {
if (i==k && j==k && k==this.SearchValue)
{
this.nextState();
return;
}
}
++this.indexJ;
setTimeout(this[this.states[this.actState]].bind(this));
return;
}
++this.indexI;
setTimeout(this[this.states[this.actState]].bind(this));
return;
}
},
yyy: function() {
// irgendwas kurzes machen
// ...
alert("durch");
this.nextState();
},
};
var xxx = new MyObj();
xxx.init();
Erstmal Danke dafür. Aber nun brauche ich doch noch gern ne Erklärung von dir ;)
function MyObj() {
}
Das ist die ehemalige (meine) init, welche ich aus dem Hauptscript aufrufe, oder?
states: [ ... ]
Sind das meine Funktionen, welche ich habe? Also da wo ich zwischen den einzelnen Funktionen meinen Status ausgeben möchte?
Und was genau machen die einzelne Schritte. Tut mir leid, dass ich deine Finger und Tastatur stresse aber wie gesagt, um es ENDLICH verstehen zu können, muss ich nachfragen. Lieben Dank schonmal von mir.
var xxx = new MyObj();
xxx.init();
Dies ruft dann die o.g. Funktion auf?
LG Romero
function MyObj() {
}Das ist die ehemalige (meine) init, welche ich aus dem Hauptscript aufrufe, oder?
Das ist dein Objekt, an dem du Werte speichern kannst.
states: [ ... ]
Sind das meine Funktionen, welche ich habe? Also da wo ich zwischen den einzelnen Funktionen meinen Status ausgeben möchte?
Eine einfache Statemachine wo die States gleich den Funktionsnamen entsprechen müssen, das würde man i.d.R noch weiter ausbauen, soll nur das Prinzip verdeutlichen.
Und was genau machen die einzelne Schritte. Tut mir leid, dass ich deine Finger und Tastatur stresse aber wie gesagt, um es ENDLICH verstehen zu können, muss ich nachfragen. Lieben Dank schonmal von mir.
var xxx = new MyObj();
Das legt eine Instanz des Objektes an. (Aber das sind Grundlagen)
xxx.init();
Startet das Ganze. Also ruft die init()-Funktion mit der Instanz xxx als Context auf (vielleicht nimmst du doch lieber eine Closure)
this.nextState(); ruft dann die Nächste auf.Wobei ich gerade sehe, da fehlt noch ein Timeout, also
setTimeout(this[this.states[++this.actState]].bind(this), 0);
Ok, erstmal danke dir.
Um es mal kurz zusammenzufassen.
Die States sind meine Funktions-Namen. Unter .prototype = { ... } und dem "Rest" was da noch so kommt :) lege ich sozusagen fest, was mit den einzelnen Funktionen passiert.
Also in etwa so:
function MyObj() {
}
MyObj.prototype = {
states: ["Excel_Tabelle_Laden", "Leere_Eintraege_Loeschen", "Daten_konvertieren", ...],
actState: 0,
indexI: 0,
indexJ: 0,
SearchValue: 60000,
nextState: function() {
if (this.actState < this.states.length - 1) {
setTimeout(this[this.states[++this.actState]].bind(this), 0);
}
},
Excel_Tabelle_Laden: function() {
// Funktionsaufruf
// ...
this.nextState();
},
Leere_Eintraege_Loeschen: function() {
// Funktionsaufruf
// ...
this.nextState();
},
Daten_konvertieren: function() {
// Funktionsaufruf
// ...
this.nextState();
},
};
var xxx = new MyObj();
xxx.init();
Ist das soweit richtig?
Und wie komme ich aus dem Hauptscript auf diesen Auszug?
Vorher wars ja so:
Hauptscript:
init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime );
-->
ausgegliederte JS:
function init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime ) {... };
Und nun so?
Hauptscript:
xxx.init();
ausgegliederte JS:
var xxx = new MyObj();
LG Romero
PS: Sorry nochmals aber möchte mein bisheriges Script nicht unnötig auseinander fetzen, sondern dass was bisher lief, erhalten lassen. Hoffe du kannst es nachvollziehen und verstehen.
Um es mal kurz zusammenzufassen.
Die States sind meine Funktions-Namen. Unter .prototype = { ... } und dem "Rest" was da noch so kommt :) lege ich sozusagen fest, was mit den einzelnen Funktionen passiert.
pfff... vielleicht, hast du es denn verstanden?
Ist das soweit richtig?
Ja, diese Variablen
indexI: 0,
indexJ: 0,
SearchValue: 60000,
waren interne Variablen von mir, die brauchst du nicht
Und wie komme ich aus dem Hauptscript auf diesen Auszug?
Vorher wars ja so:
Hauptscript:
init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime );
-->
ausgegliederte JS:
function init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime ) {... };Und nun so?
Das Anlegen der instanz gehört eigentlich mit in das Hauptscript.
Die Argumente der Funktionen wirst du glaube ich alle als Objektmember haben. Auf diese kannst du dann mit this.name zugreifen
So, an alle Mitlesern, Beantwortern und Mitratern ;)
ich habe da mal was vorbereitet:
function init_STL_Aircabin( infile_zusatz_tmp, infile_zusatz_anzahl_tmp, starttime )
{
a = 0;
var one = function( infile_Aircabin ) { infile_Aircabin = Leere_Eintraege_Loeschen( infile_Aircabin ); return infile_Aircabin; };
var three = function( infile_Aircabin ) { infile_Aircabin = Daten_konvertieren( infile_Aircabin ); return infile_Aircabin; };
//var two = function( infile_Aircabin, anzahl_Aircabin ) { anzahl_Aircabin = Leere_Eintraege_Loeschen( anzahl_Aircabin ); return anzahl_Aircabin; };
//var four = function( infile_Aircabin, anzahl_Aircabin ) { anzahl_Aircabin = Anzahl_konvertieren( anzahl_Aircabin ); return anzahl_Aircabin; };
var tt = function( infile_Aircabin) { for( var i = 0; i < infile_Aircabin.length; i++) { msg( infile_Aircabin + "<br>" ); }; };
var renderStatus = function() { Fortschritt_Anzeige( a ) };
var queue = [ one, three, tt ];
var processQueue = function( infile_Aircabin )
{
var func = queue.shift();
if (func)
{
a = a+5;
infile_Aircabin = func( infile_Aircabin );
renderStatus();
var nextStep = function ()
{
processQueue( infile_Aircabin );
};
setTimeout( nextStep, 0 );
}
};
infile_Aircabin = Excel_Tabelle_Laden( locations.infile, locations.startSheet );
//anzahl_Aircabin = infile_Aircabin;
processQueue( infile_Aircabin );
};
Ich habe anhand der Quelle (http://jsfiddle.net/molily/BfAVX/) ...
Indem die Daten von der einen Step-Funktion an die nächste weitergegeben werden. Das ist
im Grunde nur cleveres herumreichen der Daten:
http://jsfiddle.net/molily/BfAVX/
... den Code mir genau angeschaut und mittels eurer Beiträge mir das obigen JS-Gerüst zusammengebaut. Ersteinmal für mich vereinfacht, um zu schauen, ob es das ist (für mich), was ich suche bzw. was ich auch verstehe (Idee & Umsetzung).
Anhand dieses Code's ist es das, was ich möchte und es funktioniert (wie oben gescriptet) auch einwandfrei. Nun aber ne weitere Frage: Wie kann ich weitere Variablen ändern bzw. hinzufügen?
Habe es versucht, in dem Ich die Variablen "var two" & "var four" (+ die Funktionen) dazuschrieb, habe auch die processQueue( ... ), func( ... ), processQueue = function( ... ) sowie var queue = [ ... ] um "anzahl_Aircabin" erweitert. Aber er verändert die Ausgangsvariablen infile_... und anzahl_... nicht, so wie erwünscht bzw. er überschreibt dann die infile_... mit der anzahl_... .
Wie kann ich also mit mehreren Daten gleichzeitig arbeiten? Ohne das die eine von der anderen Überschrieben wird?
LG Romero
Problem selber erkannt. Hab ein Array() gebildet aus allen Variablen die ich brauche. Dann lese ich sie mittels Eingabe[n] aus.
Und somit funktioniert es. :)
LG Romero
Problem selber erkannt. Hab ein Array() gebildet aus allen Variablen die ich brauche. Dann lese ich sie mittels Eingabe[n] aus.
Besser wäre ein Objekt.
Wie kann ich also mit mehreren Daten gleichzeitig arbeiten? Ohne das die eine von der anderen Überschrieben wird?
Ich denke in deinem Fall, solltest du einfach deine bisherigen Funktionen "wrappen" und gut. Damit kannst du alles so lassen wie es ist, nur die init-Funktion muss die wrapper bereitstellen und die Abarbeitung starten.
function Excel_Tabelle_Laden(data1) {
return data1 + 1;
}
function Leere_Eintraege_Loeschen(data1, data2) {
return data1 + data2;
}
function Daten_konvertieren(data1, data2, data3) {
alert("data1: " + data1 + " data2: " + data2 + " data3: " + data3);
}
function init(data1) {
var data2, data3;
var one = function () {
data2 = Excel_Tabelle_Laden(data1);
};
var two = function () {
data3 = Leere_Eintraege_Loeschen(data1, data2);
};
var three = function () {
Daten_konvertieren(data1, data2, data3);
};
var queue = [one, two, three];
var loop = function () {
var func = queue.shift();
if (func) {
func();
setTimeout(loop, 0);
}
};
loop();
}
init(1);
Anmerkung nebenbei:
Die "bind"-Methode wird bei mir nicht unterstützt, da ich bzw. die anderen User nur mitm IE6 bzw. IE8 unterwegs sind.
LG Romero
Die "bind"-Methode wird bei mir nicht unterstützt, da ich bzw. die anderen User nur mitm IE6 bzw. IE8 unterwegs sind.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
//--> Und wie bekomm ich aus den oben genannten Funktionen meine Werte zurück?
//--> Weil vorher hatte ich es wie folgt:
// infile = function Excel_Tabelle_Laden( Ausgangswerte )
// infile = function Leere_Eintraege_Loeschen( infile )
// infile = function Daten_konvertieren( infile )
// ...
//--> also die zurückgegebenen Werte wurden für die weiteren Funktionen benutzt
http://forum.de.selfhtml.org/archiv/2013/4/t213368/#m1458691
Du kannst dir auch ein Objekt basteln, welches die einzelnen Funktionen und deinen bisherigen Returnwert als Member hat, vielleicht liegt dir das eher.
Das Prinzip ist immer das gleiche, du musst die benötugten Werte irgendwo sichern für den nächsten Teilschritt.
Dazu kannst du von globalen Variablen über den Closed-Term einer Closure bis zu Membervariablen nutzen.
Hallo,
//--> Und wie bekomm ich aus den oben genannten Funktionen meine Werte zurück?
//--> Weil vorher hatte ich es wie folgt:
// infile = function Excel_Tabelle_Laden( Ausgangswerte )
// infile = function Leere_Eintraege_Loeschen( infile )
// infile = function Daten_konvertieren( infile )
// ...
//--> also die zurückgegebenen Werte wurden für die weiteren Funktionen benutzt
Indem die Daten von der einen Step-Funktion an die nächste weitergegeben werden. Das ist im Grunde nur cleveres herumreichen der Daten:
http://jsfiddle.net/molily/BfAVX/
Hier ist eine Closure nextStep hinzugekommen, die processQueue (vormals loop) mit den neuen Daten aufruft.
Das ginge natürlich auch mit Function.prototype.bind, technisch gesehen ist es dasselbe; bind erzeugt auch nur eine Closure.
Allerdings würde ich den objektorientierten Ansatz bevorzugen, wie unknown ihn vorgeschlagen hat. Mein Beispiel oben ist eher ein funktionaler – es gibt kein geteiltes Status-Objekt, sondern nur die Arbeitsdaten, und eine Step-Funktion braucht keine Seiteneffekte zu haben. Das ist sauber, aber weniger flexibel.
Mathias
Eine andere ist das Erzwingen des Renderings durch die Abfrage von offsetWidth oder einer anderen Eigenschaft, dessen Wert der Browser erst durch Layouting korrekt zurückliefern kann.
Sicher? Meiner Meinung nach wird dann nur das Layout zu diesem Zeitpunkt neu berechnet, aber nicht gezeichnet.
Ich dachte, man kann nur durch einen modaler Dialog ein Rendering wärend JS läuft erzwingen.
Hallo,
Eine andere ist das Erzwingen des Renderings durch die Abfrage von offsetWidth oder einer anderen Eigenschaft, dessen Wert der Browser erst durch Layouting korrekt zurückliefern kann.
Sicher? Meiner Meinung nach wird dann nur das Layout zu diesem Zeitpunkt neu berechnet, aber nicht gezeichnet.
Wahrscheinlich hast du Recht, ein Reflow ist noch kein Repaint. Danke für den Hinweis.
Ich hätte besser auf requestAnimationFrame hinweisen sollen anstatt auf die oben genannten Hacks. RAF (hihi) ist explizit dazu gedacht, einen Repaint zu triggern und verhält sich ansonsten wie setTimeout hier im Thread benutzt wurde.
Mathias