érdekes JS probléma: a script először rosszul működik (MINDEN ESETBEN!), majd megjavul...
A problémát röviden a kód alatt leírom. FF3 alatt néztem. A komplett kód, ki is lehet próbálni (protoype.js):A hiba reprodukálása:
1. Kattints egymás után kétszer a Delay1 szövegre, majd gyorsan a Delay2 szövegre. Ekkor 4 új sor lesz. Normális működés esetén az 1. és a 3. sornak számolnia kellene. És 10 másodperc alatt mindenhol azt kéne kiírnia, hogy kész, de ezzel ellentétben 20 másodperc alatt megy végig és egyesével.
2. Várd végig, míg mind a négy sornál azt írja ki, hogy kész. Most ismételd meg az előző lépést. Kettőt kattints a Delay1-en és kettőt a Delay2-n. Láss csodát, normálisan működik.
A probléma röviden: Van egy időzítő (Timer), ami az oldal betöltése után elindul és fél másodpercenként meghívogatja a neki átadott objektumokat (egészen pontosan az objektumok runTimer() fv-ét). Itt a példában két objektumot kap kattintásra, amik azt csinálják, hogy várakoznak 5 másodpercet, annyiszor, ahányszor rákattintasz. Amikor az elsőre kattintok, akkor elindul a számláló. Ha ugyanekkor a másodikra, akkor annak is számolnia kellene! De nem ezt csinálja :( A this.current-re az első objektum current-jét használja! De csak az elején. Ha végigvárom a kattintások eredményeit, majd újra kattintok, akkor már minden jól működik. Miért??? A logban látszik, hogy egy darabig a másodikként elindított várakoztató az elsőnek az objektumával "dolgozik". Ugyanakkor néha a saját delayStart változóját használja, néha az elsőnek létrehozott objektumét... IE alatt nem is akar működni, a hibakeresője teljesen használhatatlan és értelmetlen üzeneteket ad. Nem a hiba valódi okát adja meg. Most a hiba az én gépemben van (telepítsem újra? :D ), vagy a scriptben?
Ha a hibát reprodukálod, a logban látható, hogy a Delay1 (d1) és a Delay2 (d2) ugyanazzal az elemmel foglalkozik (szögletes zárójelbe írt szám), tehát a this.current mindkettőjük esetében ugyanaz! DE! A this.delayStart (sima zárójelbe írt szám) meg mégsem ugyanaz, azt jól kezeli, tehát nem keveri a két objektum adatát.
Tehát: hol a hiba, hogy ez így működik? (tegnap este még működött rendesen, ma mikor bekapcsoltam újra a gépet, azután kezdte el ezt)
IE alatt tegnap sem működött, tudna vki segíteni, hogy miért nem? Nem vagyok vmi nagy JS guru :( (még :) )
Az "Objektumorientált JavaScript programozás a felszín fölött" cikket olvastam, úgyhogy ha ott van válasz, csak én siklottam el felette, akkor vissza lehet rá utalni, és akkor előre is elnézést kérek :)
■ - <html>
- <head>
- <script language="javascript" src="prototype.js"></script>
- <script type="text/javascript">
- /**
- * Timer
- * Időzítő. Amint betöltődött az oldal fél másodpercenként lefut.
- */
- var Timer = {
- // Ebben a tömbben tárolja, hogy mely objektumok runTimer() fv-t kell meghívni minden fél másodpercben.
- container: [],
- // Ebben a változóban követjük, hogy befejeződött-e az előző hivás, és ha nem, akkor nem hívható kétszer egymás után!!!
- isRun: false,
- // Itt nézzük, hogy el lett-e már indítva az időzítő
- isStarted: false,
- // Itt adunk hozzá új visszahivandó objektumot.
- add: function(element, overwrite) {
- added = this.hasAdded(element);
- if(!overwrite && added) {
- return false;
- } else if(added) {
- this.remove(element);
- }
- this.container[this.container.length] = element;
- return true;
- },
- // Itt távolítjuk el a megadott objektumot, ha arra már nincs szükség.
- remove: function(element) {
- thisthis.container = this.container.without(element);
- },
- // Megnézi, hogy a megadott elem hozzá lett-e már adva.
- hasAdded: function(element) {
- return (this.container.indexOf(element)>=0);
- },
- // Elindítja az időzítőt
- start: function(event) {
- // Csak akkor lehet elindítani az időzítőt, ha az még nincs elindítva.
- if(!this.isStarted)
- {
- window.setInterval('Timer.run()', 500);
- this.isStarted = true;
- }
- },
- // Ezt hívja meg fél másodpercenként
- run: function() {
- if(!this.isRun) {
- // Elkezdődik a tömb bejárása
- this.isRun = true;
- // Az objektumoknak átadja a az aktuális időpontot
- d = new Date();
- // Bejárja a container tömböt és egyesével meghívja az ott lévő objektumok callTimer() fv-ét
- this.container.each(function(element) {
- element.callTimer(d);
- });
- // Befejeződött a tömb bejárása
- this.isRun = false;
- }
- }
- }
- // Várakoztató "osztály". Több ilyen is lehet. Akkor kerül egy "várakoztatóba" két objektum,
- // ha a második csak akkor kezdődhet el számolni, ha az előző már lefutott
- var Delayer = Class.create({
- // Mikor kezdett el várakozni a this.current elem.
- delayStart: null,
- // Az aktuálisan várakozó objektum
- current: null,
- // Az objektum lista, ami várakozik
- container: [],
- // Éppen várakozik-e vmi
- isRun: false,
- name: null,
- initialize: function(name) {
- this.name = name;
- },
- start: function(element) {
- this.container[this.container.length] = element;
- Timer.add(this, false);
- },
- // Eltávolít egy várakozó objektumot
- cancel: function(element) {
- thisthis.container = this.container.without(element);
- },
- // Alaphelyzetbe állítja a "várakoztatót"
- reset: function(element) {
- // Törli az elemet a listáról
- if(typeof(element)!='undefined') {
- this.cancel(element);
- }
- this.current = null;
- this.delayStart = null;
- if(document.test) {
- document.test.logta.value+="----- Reset: "+this.name+"\n";
- }
- },
- // Eggyel továbblépteti a várakozó elemek listáján.
- next: function(d) {
- // Ha nincs több elem, akkor kilép
- if(this.container.length==0) {
- this.reset();
- return false;
- }
- thisthis.current = this.container.first();
- this.delayStart = d;
- return true;
- },
- callTimer: function(d) {
- // Ha az aktuális elem null és nincs tovább
- if(this.current==null && !this.next(d)) {
- Timer.remove(this);
- return false;
- }
- document.test.logta.value+=d.getTime()+": "+this.name+" ("+this.delayStart.getTime()+") ["+this.current.n+"]\n";
- // Ennyi másodpercet kell várnia az adott objektumnak
- w = this.current.wait;
- // Ennyi másodperc van még hátra
- distance = w-parseInt((d.getTime()-this.delayStart.getTime())/1000)-1;
- if(distance>0) {
- this.current.status('Hátra van:'+distance+' s');
- } else {
- this.current.run(d);
- this.reset(this.current);
- }
- },
- });
- var Obj = Class.create({
- // Az objektum sorszáma
- n: 0,
- // Ennyi másodpercet várjon
- wait: 5,
- // ahova írkálnia kell
- html: null,
- initialize: function(n) {
- this.n = n;
- this.html = new Element('div', {'id': 'obj_'+n}).update('init');
- document.body.appendChild(this.html);
- },
- run: function(d) {
- this.status('Kész: '+this.n);
- },
- status: function(msg) {
- this.html.update(msg);
- }
- });
- var counter = 0;
- var d1 = new Delayer('d1');
- function startDelay1() {
- document.test.logta.value+="+++++ Klikk: Delayer1\n";
- d1.start(new Obj(counter));
- counter++;
- }
- var d2 = new Delayer('d2');
- function startDelay2() {
- document.test.logta.value+="+++++ Klikk: Delayer2\n";
- d2.start(new Obj(counter));
- counter++;
- }
- </script>
- </head>
- <body>
- <script>
- document.body.onload = Timer.start();
- </script>
- <form name="test">
- <textarea name="logta" cols="100" rows="40" style="float: right"></textarea>
- </form>
- <div id="message" onclick="javascript: startDelay1()">Delayer1</div>
- <div id="message2" onclick="javascript: startDelay2()">Delayer2</div>
- </body>
- </html>
1. Kattints egymás után kétszer a Delay1 szövegre, majd gyorsan a Delay2 szövegre. Ekkor 4 új sor lesz. Normális működés esetén az 1. és a 3. sornak számolnia kellene. És 10 másodperc alatt mindenhol azt kéne kiírnia, hogy kész, de ezzel ellentétben 20 másodperc alatt megy végig és egyesével.
2. Várd végig, míg mind a négy sornál azt írja ki, hogy kész. Most ismételd meg az előző lépést. Kettőt kattints a Delay1-en és kettőt a Delay2-n. Láss csodát, normálisan működik.
A probléma röviden: Van egy időzítő (Timer), ami az oldal betöltése után elindul és fél másodpercenként meghívogatja a neki átadott objektumokat (egészen pontosan az objektumok runTimer() fv-ét). Itt a példában két objektumot kap kattintásra, amik azt csinálják, hogy várakoznak 5 másodpercet, annyiszor, ahányszor rákattintasz. Amikor az elsőre kattintok, akkor elindul a számláló. Ha ugyanekkor a másodikra, akkor annak is számolnia kellene! De nem ezt csinálja :( A this.current-re az első objektum current-jét használja! De csak az elején. Ha végigvárom a kattintások eredményeit, majd újra kattintok, akkor már minden jól működik. Miért??? A logban látszik, hogy egy darabig a másodikként elindított várakoztató az elsőnek az objektumával "dolgozik". Ugyanakkor néha a saját delayStart változóját használja, néha az elsőnek létrehozott objektumét... IE alatt nem is akar működni, a hibakeresője teljesen használhatatlan és értelmetlen üzeneteket ad. Nem a hiba valódi okát adja meg. Most a hiba az én gépemben van (telepítsem újra? :D ), vagy a scriptben?
Ha a hibát reprodukálod, a logban látható, hogy a Delay1 (d1) és a Delay2 (d2) ugyanazzal az elemmel foglalkozik (szögletes zárójelbe írt szám), tehát a this.current mindkettőjük esetében ugyanaz! DE! A this.delayStart (sima zárójelbe írt szám) meg mégsem ugyanaz, azt jól kezeli, tehát nem keveri a két objektum adatát.
Tehát: hol a hiba, hogy ez így működik? (tegnap este még működött rendesen, ma mikor bekapcsoltam újra a gépet, azután kezdte el ezt)
IE alatt tegnap sem működött, tudna vki segíteni, hogy miért nem? Nem vagyok vmi nagy JS guru :( (még :) )
Az "Objektumorientált JavaScript programozás a felszín fölött" cikket olvastam, úgyhogy ha ott van válasz, csak én siklottam el felette, akkor vissza lehet rá utalni, és akkor előre is elnézést kérek :)
Most komolyan?
Ez már az egyszerűsítés után van :)
Az eredeti kód ennél jóval hosszabb, ez már gyomlálás után van, de az észrevételed után tovább kopasztottam, most már tényleg csak a lényegi rész van benne.
IE probléma megoldva. A bemásolt kód 138. sorában van egy vessző, ami nem tetszett neki. Persze a világért sem ezt írta ki... Szinte soronként elkezdtem átmásolni egy másik fájlba a forrást, úgy találtam meg a hibát.
Átírtam, így már működik IE alatt is, és ott is ezt a tünetet produkálja. Itt az új kód:
A gond tehát az, hogy létrehozok két "várakoztatót". Legyenek ezek mondjuk jegyellenőrök. A jegyellenőrnek meg van mondva, hogy a biztonsági emberke 5 másodperc alatt ellenőriz le egy vendéget. A jegyellenőr feladata, hogy pontosan 5 másodperc múlva engedje tovább a vendéget, addig ne! A jegyellenőr és a biztonsági emberke egyszerre csak egy emberrel tud foglalkozni, így ha egy ellenőrhöz 2-3 ember áll be a sorba, akkor szépen mindegyiknek ki kell várnia a sorát. (a container tömbbe kerülnek az "emberkék")
Esetünkben viszont a gyorsabb haladás miatt két jegyellenőr van létrehozva, így az emberek két helyre is állhatnak. Amikor a Delay 1-re kattintasz, akkor egy emberkét beállítasz a sorba az 1. jegyellenőrhöz, a Delay 2-nél pedig a 2. jegyellenőrhöz.
Ha 4 emberkéd van, és 2-2 emberkét állítasz be a sorba, akkor 10 másodperc alatt mindnek be kéne jutnia. Ellenben a scriptnél a következő történik:
Beállítasz 2-2 embert, a két jegyellenőrhöz. Csakhogy nem külön-külön elkezdenek foglalkozni a sajátjaikkal, hanem mindkettő ugyanazzal az emberrel foglalkozik! A 'this.container' változó mintha mindkét objektumban "megegyezne", így mikor hozzáadok egy-egy emberkét mindkét sorhoz, abból nem két sor lesz, hanem 1! De csak amíg be nem jut mindegyik ember, és üres nem lesz mindkét sor. Mert ha ekkor megint hozzáadok 1-1 embert a jegyellenőrökhöz, akkor már 2 sor fog kialakulni és helyesen működik, tehát a 'this.container' már mindkét objektumban más!
Máshogy, nagyon lebutítva, csak a tünetre koncentrálva:
Ugyanaz
Nem
Nem értem
+++++ Klikk: Delayer[12]
illetve egy init felirat jelenik meg és ennyi.
prototype
Erre nem is gondoltam...
prototype
prototype
onload
Valóban