ugrás a tartalomhoz

Egyedi esemény és eseménykezelő javascript-ben.

s_volenszki · 2008. Május. 22. (Cs), 20.48
Gondolatban elkezdtem építeni egy webes alkalmazás futtató környezetet. Az alkalmazások amik ebben futnak, értelem szerűen statikus és dinamikus html+css+js kódok összessége.

Alapvetően két különböző kisalkalmazást különböztetek meg:

- Felhasználói beavatkozást igénylő
- Felhasználói beavatkozást nem igénylő

A felhasználói beavatkozást igénylő kisalkalmazások adatokat kérnek be és azokkal végeznek munkát. Például új rekord rögzítéséhez kér be adatokat.

A felhasználói beavatkozást nem igénylő kisalkalmazások többnyire az oldal szerkezeti változásait hivatottak elvégezni. Többnyire olyan folyamatok következményei amelyek igényelnek felhasználói beavatkozás, például egy adatbevitel után frissít egy táblázatot.

Alapvetően a felhasználói beavatkozást nem igénylő kisalkalmazásokkal nem lenne semmi macera, mert lineárisan futnak le (a részfolyamatok egymást követik), viszont a felhasználói beavatkozást igénylő folyamatoknál, míg egy betöltött űrlappal vacakol a felhasználó, megszakad a kisalkalmazás folyamatossága. Nem beszélve arról, hogy az űrlap folyamata több különböző állapotba is kerülhet a folyamat végére. Lehet ugye igaz, ha a tőle elvárt folyamat teljesült, lehet ugye hamis, ha nem teljesült és keletkezhetett hiba is!

Ezek alapján ha szétbontom a kisalkalmazást több különálló folyamatra:

Adatbekérő űrlap betöltése és megjelenítése
Adatbekérő űrlap dolgozik (ez nem tudjuk meddig fog tartani, ezért itt fizikilag megszakad a folyamat)
Adatbekérő űrlap eredményének elbírálása és az eredmények alapján a folytatás

Arra gondoltam, hogy lehetne minden kisalkalmazásnak egy folyamatlistája logikai kitételekkel együtt. Így ha eljut a folyamat az állapottalansághoz akkor valójában megszakad a kisalkalmazás futtatása és a kisalkalmazás értelmező fülel, várja az éppen folyamatban lévő, de számára állapottalan folyamat kimenetét. Ha az végez, az értelmező elkapja az eredményt, behelyettesíti a folyamatlistába és minden halad tovább.

Ez azért lenne jó, mert például ha az a bizonyos űrlap AJAX-szal van elküldve és keletkezik egy kommunikációs hiba, akkor tudna dobni egy errort, amit az értelmező elkapna és megalkotná az oda vonatkozó hibaüzenetet. Vagy egy új adat rögzítése után felkínálhatná a lehetőséget, hogy szerkeszti-e user az újonnan rögzített rekordot vagy sem! És ha ez a jóváhagyó dialógus true-t dob, akkor miután az értelmező azt elkapja, indulhat az új kisalkalmazás az adatok szerkesztésével.

Eljutottam hát a kérdésemig, remélem még megtudtok szólalni (hatszor futottam neki mire le tudtam írni...ennyire sikerült értelmesre), hogyan lehet javascript-tel teljesen egyedi eseményeket és eseménykezelőt definiálni?
 
1

MIt szabad használni?

Ustak · 2008. Május. 22. (Cs), 22.14
Ha jól értettem, akkor valami olyasmire van szükséged mint a jquery ajaxos metódusaiban (és egyebekben is) a "callback" artumentumok (függvények). Magyarul, mikor visszajön a request eredménye, az esemény meghívja a callback függvényt, ahol attól függően, hogy mi a szándékod ,el lehet bírálni a további folyamatok indítását, adatok feldolgozását, események hívását, stb.
Pillants reá erre:
http://docs.jquery.com/Ajax
Persze meg lehet írni önönmagadnak is (várakozósorokba a requestek, stb) de nagyon nyüszi, böngészőinkompetenciák (van ilyen szó!!!???:-)) csomó dolog amit már itt (a jqueryben) megírtak és kivédtek.
Persze van más js függvénykönyvtár is, de annak többen sem bírjuk leírni a nevét (script...scripo..ououous:) :) :))
És ha még egy jó ötletet adhatok, már most válaszd szét a szerveroldalt és a kliensoldalt, (pl php-t a javascripttől) mert iszonyú gáz lesz utána debugolni az ilyen dolgokat:
echo "<script> var=fuggvenykem("'.$valtozo.'");</script>"; Borzalmas! :)
De lehet hogy csak nékem borzalmas :-) Remélem segített valamit, meg egyáltalán sikerült a kérdésre válaszolni :)
2

Gondoltam, hogy nem lesz egyszerű...

s_volenszki · 2008. Május. 22. (Cs), 23.40
Az AJAX-os példa részben jó, de nem a callback miatt, hanem ahogyan az AJAX request működik (át is fogom nézni, hgyan működik pontosan).

Nekem arra lenne szükségem. Elindítok egy folyamatot (ahogyan az AJAX kérés elindul) és teljesen mindegy, hogy 1 perc vagy 60 perc múlva (tudom, vannak a http kérésnek időkorlátai de itt éppen még http kérés sincs és az álapotalanság a lényeg), amikor megérkezik a válasz a folyamat megy tovább a visszatérési adatok függvényében.

Képzelje el egy olyan folyamatot, ahol egyszer csak fel kell tenni egy eldöntendő kérdést, ami nem confirm(), hanem dhtml popup Ok és Mégsem gombokkal! Amikor megjelenik, megszakad a folyamat, mert vár a felhasználói inputra.

Én azt szeretném, hogy ebben az esetben tárolt processz listből dolgozzon az értelmező, és ha az Ok vagy a Mégsem gomb megnyomásra kerül, akkor fojtatódjon a process list. Ne a DHTML kérdező dialógusom indítsa a soron következő lépést, hanem csináljon olyan eseményt amiből értelmezhető egy true, fals vagy error érték és az értelmező eldönti, minek kell következnie.

A DHTML popup olyan eseményt generál, amit az egyedi eseméyn kezelő elkap (valószínüleg valami window. vagy document.), értelemz és folytatja a folyamatokat.
3

Nem triviális

zila · 2008. Május. 23. (P), 09.54
Nem egyszerű a feladat. A problémák ott kezdődnek, hogy a js futása nem fog megállni egy dhtml popup megjelenítésekor, hacsak nem prompt-ot vagy confirm-öt használsz. Ellenkező esetben bizony megjelenik a popup és a scripted vígan fut tovább. Annyit tudsz tenni, hogy a popup megjelenítésekor bebillentesz egy flag-et, és a flag állapotától függően folytatja a futását a scripted. A popup bezárása/popup-on végzett adatbevitel lekezelése után egy callback-kel visszaugrassz a meghívás helyére (abba függvénybe ahol kinyitottad a popupot), természetesen a megfelelő flag-ek átállítása után (pl. tudnia kell a függvénynek, hogy a popup már kinyílt, adatot bekérte így nem kell újra kinyitni, a korábban a popup miatt átugrott kódrészt már nem kell átugrani stb.

A prototype windows lib-ben van egy olyan megoldás, hogy az ablakok eseményeire tudsz megfigyelőket aggatni (observer) és a megfelelő ablakesemény (onClose, onMove, onMaximize stb.) bekövetkeztekor ezeket a megfigyelőket meghívja, hogy csinálják a dolgukat.

Ugyanez pepitában YUI event: http://www.dustindiaz.com/custom-events/
Vagy jMaki: https://ajax.dev.java.net/publishsubscribe.html
(Egyébként a jMaki-t érdemes szemügyre venni, igen hasznos kis jószág, most ismerkedek vele...)
5

Én nem értem?

Ustak · 2008. Május. 23. (P), 20.08
Most lehet hogy én nem értem mi a baj, de nem értem mi a baj.
A closure-k ha jól emlékszem arra valók, hogy egy bizonyos változó értékét megőrizzük azután is, hogy a js kód lefutott, magyarul a kód (függvény) "emlékszik" hogy mi volt az adott változó értéke, ojjektumorientáláskor jól jönnek, bár már régen olvastam erről a részéről a js-nek (nem is nagyon használtam, pedig jó).
Az ajax ugye asynchronous (ha akarjuk) (ez az első A :-)) és ezért gyakorlatilag nem tűnik fel a felhasználónak, hogy request megy a háttérben, tehát nem fog fagyni az oldal (jó esetben). Elmegy a request, szépen várjuk az onreadystatechange esemény változását. Közben mehetnek új requestek pl. Ha valami történik, akkor jön a függvény, ami kezeli. művelet művelet hátán, eljutunk oda hogy a felhasználónak csinálni kell valamit. Kijön a Dom div csillivilli ablak, visibility=visible vagy akár egy új createElement('div') és egyéb vezérlők belé. És ezen gombok, vagy textboxok vagy akármik eseménykezelői már új függvényeket hívnának meg, esetleg ha kell új requestel vissza a szerverhez, és stb. Én ezt így csinálnám, nem pedig egy nagy folyamatként nézném.
De lehet hogy rosszul értem a dolgot, akkor bocsi :).
6

Nem értetted rosszul!

s_volenszki · 2008. Május. 23. (P), 21.31
Igen, jól értetted, és az alapelképzelés szerint így is működik, hogy a DTHML popup eredményül megív egy fügvényt, ezzel folytadódik az előre kijelölt út.

Az elképzelésem szerint viszont az a kisalkalmazás értelmező ami elindítja a kisalkalmazás folyamatot, az irányít végig, azaz a keletkező állapotok alapján levezényel egy előre meghatározott forgatókönyvet, és nem a színész szól (a DHTML popup) a jelenetben a rendezőnek, hogy heló, most a "B" verzió szerint haladunk tovább.

Igazából, ahogyan olvasom a hozzászólásaitokat, és megnéztem a prototype observ és jQuery bind funkciókat, valójában az is elég lehet, ha a folyamat valóban megáll, természetesen úgy, hogy tárolódik a folyamat azonosítója meg az állapota, és mikor kész az input, az indít egy olyan általános függvényt (egy amolyan callback-et) amivela folyamat tud folytatódni.
8

Mel Gibson! :-)

Ustak · 2008. Május. 23. (P), 23.05
nem a színész szól (a DHTML popup) a jelenetben a rendezőnek, hogy heló, most a "B" verzió szerint haladunk tovább.

Akkor fogjuk fel úgy, hogy ez egy olyan szinészfolyamat, amely rendezővé avanzsál, a való élet példája alapján :-)
Szerintem egy olyan nyelvnél mint a javascript, elég ha az elképzelésed megvan az adott kisalkalmazásról, amit mégis sok kicsi folyamat (függvény) rak össze. Na jó, lehetne mondjuk a kisalkalmazás egy osztály (ojjektum :-)) és a metódusai a folyamatok... Elég képlékeny nyelv, és sok "design pattern"-t kitaláltak már rá. Én ezt a folyamatos egységet nem erőltetném szigorúan.
9

Elgondolkodtató...

s_volenszki · 2008. Május. 24. (Szo), 06.21
Lehetséges, hogy a tudatosság már épp elegendő körültekintés a programkörnyezet tekintetében és ehhez mérten a legrugalmasabb megoldás a célravezető...

s_volenszki

off:
Egyszer már majdnem postoltam egy érdekes jelenséggel kapcsolatban, de akkor nem volt egyértelmű, most az! A labor szerverórája késik egy órát!
4

Closure

vbence · 2008. Május. 23. (P), 10.10
Ugyebár lieárisan ez lenne:

function beker() {
    var i = 1;
    var n = 33;
    ...
    if (input = dhtmlBlockingInput()) {
        // formfeldolgozás
        alert(n + input["mezo1"]);
    }
    // itt nincs már SEMMI
}
Ez viszont így nem valósítható meg, azon egyszerű okból, hogy a JS nem definiál egy sleep() függvényt, amivel szépen lehetne időnként vizsgáli egy párhuzamos műveletet. Sőt az átlagos JS platformok (böngészők) egyáltalán nem támogatnak párhuzamos művelezteket (általában az összes többi ablak "fagy" amég az egyikben éppen fut a JS).

Ha viszont a fenti logikára van szükséged, akkor az egy eseménykezelés + záradék módszerét hazsnálhatod az azonos hatás eléréséhez:

function beker() {
    var i = 1;
    var n = 33;
    ...
    dhtmlBlockingInput(function (input) {
        // formfeldolgozás
        alert(n + input["mezo1"]);
    });
    // ami itt lenne az késleltetés nélkül lefutna
}
Persze else ágat is használhatsz, csak annyit kell tenned, hogy a második esetben beírod az if-et az eseménykezelőbe, és annak már lehet több ága is.
7

Ezt nem teljesen értem.

s_volenszki · 2008. Május. 23. (P), 21.34
Ezt nem teljesen értem, de valószínüleg azért, mert nem ismerem a closure fogalmát, utánajárok!

Köszönöm mindenkinek,
s_volenszki
11

Nem a fogalom a lényeg

vbence · 2008. Május. 24. (Szo), 14.43
... hanem csupán az, hogy a fenti eset (ami feltételezi, hogy létezik blokkoló folymaat JSben) megcalósítható normál JSben az alsó módszerrel.
10

cseberből függvényverembe

toxin · 2008. Május. 24. (Szo), 07.54
héten volt egy hasonló feladatom: layer popup-ok összefűzését kellett megoldanom, miszerint egy A popupról hívott B popup: cancel esetén vissza tudjon térni A-ra ill. A popup a B popup-on megtörtént eseménytől ill. annak eredeményétől függően folytassa a működését, ha jól értem a fentieket A helyére Director-t, B helyére Actor-t írva:
			var callbackStacker  = function() {				
				this._callbackStack = [];													
			};
			
			callbackStacker.prototype.pushCallback = function(dispachTo,callback/*function,function*/){
					this._callbackStack.push(callback);
					dispachTo();
			};
				
			callbackStacker.prototype.popCallback = function(/*any*/){
					this._callbackStack.pop().apply(this,arguments);
			};
			myCallbackStack = new callbackStacker;
			
			
			var Director = {
				
				start : function(){
					//closure, put Director/this into the call object
					var that = this;
					//  call Actor with dispatch function, putting the callback function into the stack
					myCallbackStack.pushCallback(
						//dispatcher function
						function(){
							Actor.start({
								question : "Are you satisfied?"
							})
						},
						// return function
						function(params/*any*/){
							if (params) that.eventA(true); else that.eventB(false);
						}
					);
				},
				
				eventA : function(param/*any*/){
					alert("that's fine")
				},
				
				eventB : function(param/*any*/){
					alert("but why? :S");
				}
								
			};			
			
			var Actor = {				
				start : function(params/*any*/){
					if (window.confirm(params.question)){
						// call return function with true param
						myCallbackStack.popCallback(true);
					}else{
						// call return function with false param
						myCallbackStack.popCallback(false);
					};					
				}				
			};
			
			Director.start();		
magyarán egy verembe(last in - first out tárolóba) bedobáljuk a callback függvényeket és visszatérés esetén meghívjuk őket, az Actor-nak is lehetnek további Actor-jai, a verem tölthető tovább a visszatérési lánc - verem működni-töltődni fog.

remélem valami ilyenre gondoltál, ha nem folyt köv. :)

üdv Csaba
12

Szerintem ez tök jó

Ustak · 2008. Május. 24. (Szo), 15.08
Én is valami hasonlót csinálnék, szerintem ez nagyon ötletes.
Legalábbis az elméletnek mindenképpen ezt a szálat kellene követnie.