Seminar Höllische Programmiersprachen im Wintersemester 2014

Werbung
Seminar Höllische Programmiersprachen im
Wintersemester 2014/15
Callbacks und Event Handlers
Vanessa Robl
Technische Universität München
18.12.2014
1
Zusammenfassung
Callbacks und Event Handlers sind Funktionalitäten, die beim Programmieren in einigen verschiedenen Sprachen genutzt werden.
In dieser Arbeit wird vorgestellt, in welchen Bereichen sie eingesetzt werden und welchen Nutzen sie für den Programmierer haben. Mit Codebeispielen aus den Programmiersprachen HTML, JavaScript und Visual C#
wird näher darauf eingegangen, wie die Anwendung in der Praxis aussieht.
Es werden außerdem möglicherweise auftretende Probleme und zugehörige Lösungsansätze und Alternativen diskutiert. Des Weiteren werden Vorund Nachteile abgewogen, die abschließend mit einer kurzen Abschätzung
der zukünftigen Entwicklung verknüpft werden.
2
Inhaltsverzeichnis
1 Definitionen und Begriffseinführung
1.1 Was ist ein Callback . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Was ist ein Event Handler . . . . . . . . . . . . . . . . . . . . . .
4
4
4
2 Verwendung in Programmiersprachen
2.1 Anwendungsgebiete . . . . . . . . . . . . . . . . . .
2.1.1 Event-Handler als Bindeglied zwischen User
2.1.2 Gemeinsame Verwendung von Callbacks
Handlers . . . . . . . . . . . . . . . . . . . .
2.1.3 Weitere Anwendungsgebiete für Callbacks .
2.2 Probleme bei der Verwendung . . . . . . . . . . . .
2.3 Lösungsansätze für auftretende Probleme . . . . .
5
5
5
3 Pro und Contra der Anwendung
3
. . . . . . . .
und Skript .
und Event. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
7
8
10
11
13
1
Definitionen und Begriffseinführung
Diese Arbeit thematisiert die Verwendung von Callbacks und Event Handlers.
Es werden Anwendungsgebiete sowie möglicherweise auftretende Probleme und
passende Lösungsansätze zu diesen Problemen aufgezeigt und diskutiert. Im Folgenden werden zuerst alle Begrifflichkeiten definiert und Codebeispiele gezeigt.
1.1
Was ist ein Callback
Eine Callback-Funktion ist eine Funkion (mit oder ohne Rückgabewert), die als
Parameter für eine Standardfunktion verwendet oder als Objekt gespeichert
werden kann. Sind die richtigen Bedingungen erfüllt, so kann die Funktion
aufgerufen und ausgeführt werden. Allgemein gilt, dass Callback-Funktionen
nicht statisch sind, sondern erst zur Laufzeit des Programms eingebunden
werden.
Einsatzgebiet für Callbacks sind zum Beispiel Asynchrone Programmierung und
GUI-Events. Übergibt man einer Methode die Callback-Funktion als Argument,
so wird sie zu einem bestimmten Zeitpunkt, den der Programmierer selbst
festlegen kann, aufgerufen. Wird sie sofort ausgeführt, nennt man das einen synchronen Callback, ansonsten einen asynchronen. Für die GUI-Programmierung
sind Callbacks deshalb gut geeignet, weil sie als Rückgabewert eine Funktion
haben. So können mit ihnen auch bei Funktionsreferenzen Parameter übergeben
werden, was bei Standardfunktionen nicht möglich ist. Callbacks sind insgesamt
ein ideales Strukturmittel fr ereignisorientierte Programmierung.
Ein Beispiel dafür, wie das Grundgerüst einer Callback-Funktion in JavaScript
aussehen kann, ist Folgendes:
1
3
5
function callMe ( ) {
return function () {
// do s o m e t h i n g
};
}
Eine Callback-Funktion ist letztendlich also ein Verfahren, das beim Eintreten
eines Ereignisses gezielt eine bestimmte Funktion aufruft [13].
1.2
Was ist ein Event Handler
Event-Handler sind Mechanismen, die auf bestimmte Ereignisse (z.B. einen
Mausklick) reagieren und die die Callback-Funktion, die diesen Ereignissen
zugewiesen wurden, aufrufen. Somit ist die Implementierung von der Verwendung getrennt. Sie haben den Vorteil, dass mit ihrer Anwendung ein
Programm nicht mehr in einer Schleife auf ein Ereignis warten muss, sondern
erst bei dessen Auftreten aktiv wird. Deswegen werden Event-Handler bei der
ereignisorientierten Programmierung verwendet. Jeder Event-Handler steht
4
dabei für ein bestimmtes Anwendungsereignis [12].
Der Name eines Handlers beginnt in vielen Sprachen mit “on”. In JavaScript
sieht die zugehörige Syntax (hier im Beispiel der Handler joinList) wie folgt aus:
1
3
var j o i n L i s t = f u n c t i o n ( ) {
a l e r t ( ” H i e r s t e h e n d i e Anweisungen f ü r d i e Funktion ” ) ;
}
Soll nun dieser Handler an ein direktes Ereignis (hier ein Klick auf einen
Button) geknüpft werden, so schreibt man:
1
document . getElementById ( ” submit \ b u t t o n ” ) . o n c l i c k = j o i n L i s t ;
Bevor solche Verknüpfungen stattfinden können, müssen aber erst das Objekt
und das Ereignis, das den Event-Handler triggert, spezifiziert werden.
Event-Handler sind primär das Bindeglied zwischen der graphischen Oberfläche
und dem Code [10].
2
Verwendung in Programmiersprachen
Callbacks und Event Handlers sind vor allem in GUI-Programmen nützliche
Elemente. Im Folgenden werden direkte Anwendungsbeispiele in den Sprachen
HTML und JavaScript sowie Visual C# betrachtet. Außerdem kommen auftretende Probleme, wie zum Beispiel die “Callback-Hell”, zur Sprache und mögliche
Lösungsansätze werden diskutiert.
2.1
2.1.1
Anwendungsgebiete
Event-Handler als Bindeglied zwischen User und Skript
Event-Handler werden bei der Programmierung mit visuellen Komponenten benutzt, bei denen eine Art von Interaktion zwischen User und Code vonnöten
ist, am häufigsten für Webseiten. Oft werden sie als Bindeglied zwischen HTML
und JavaScript benutzt und dabei meist in Form von Attributen in HTML-Tags
notiert, über die sich dann JavaScript aktivieren lässt. Ein Tag ist ein Codeelement, das in spitze Klammern eingeschlossen ist. In HTML wären solche
Elemente zum Beispiel <link >, <script >, <section> oder <h1> [10].
Betrachten wir das HTML-Attribut onClick in folgendem Beispielcode:
5
1
3
5
<INPUT
TYPE = ” checkbox ”
NAME = ” o p t s ”
VALUE = ” g r o s s −k l e i n ”
o n C l i c k = ” g r o s s −k l e i n=t h i s . c h e c k e d ; ”
>
Der String-Wert in onClick kann eine oder mehrere JavaScript-Anweisungen
beinhalten. Sind es mehrere Anweisungen, so müssen diese durch ein Semikolon
getrennt werden. Tritt nun dieses Ereignis, das onClick zugeordnet wurde, ein
(hier ein Mausklick), wird die Anweisung, die innerhalb des Strings steht, ausgeführt. Damit JavaScript und HTML möglichst voneinander getrennt bleiben
und der Code übersichtlich ist, wird – wenn mehrere Anweisungen vorhanden
sind – üblicherweise der Rumpf des Event-Handlers als Funktion definiert und
diese Funktion dann über den Event-Handler aufgerufen. Dabei wird die Funktion zwischen den Tags <SCRIPT > und </SCRIPT> definiert.
Das Attribut onClick wird zum Beispiel für Buttons, Checkboxen und RadioButtons verwendet. Bei Textelementen können andere Event-Handler benutzt
werden, wie beispielsweise onchange(), onfocus() oder onblur(). In Tabelle 1
werden ein paar von JavaScript unterstützte Handler zusammen mit ihrem jeweiligen Einsatzgebiet aufgeführt [6].
Tabelle 1: Event-Handler in JavaScript
Event-Handler
onBlur
onClick
onChange
onFocus
onLoad
onMouseMove
Aufgerufen, wenn...
wenn ein Objekt den Tastaturfokus
verliert
wenn der Benutzer auf ein Objekt klickt
wenn sich der Wert eines Objektes
ändert
wenn ein Objekt den Tastaturfokus
erhält
wenn ein Objekt geladen worden ist
wenn der Benutzer die Maus bewegt
Unterstützt von
Element, Window, Layer
Document, Button, Checkbox,
Link, Radio, Reset, Submit
Element, FileUpload, Passwort,
Select, Text, Textarea
Element, Window, Layer
Document, Image, Window, Layer
keinem Objekt; wird nur aufgerufen nach Anforderung durch captureEvents()
Bei der Implementierung ist darauf zu achten, dass JavaScript im Unterschied
zu HTML Groß- und Kleinschreibung unterscheidet und dass Event-HandlerEigenschaften in JavaScript komplett klein geschrieben werden. Man kann
Event-Handler selbst definieren oder verändern, indem man ihnen bestimmte
Funktionen zuweist [6].
6
2.1.2
Gemeinsame Verwendung von Callbacks und Event-Handlers
Oft werden im Zusammenhang mit Event-Handlers Callbacks verwendet, sodass
die Struktur und die Funktionalität nicht vermischt werden. Um das gewünschte
Ergebnis zu liefern, muss dem Event-Handler eine Funktionsreferenz übergeben
werden, also ein Zeiger auf eine Funktion. Einer solchen Referenz können jedoch
keine Parameter mitgegeben werden. Dieses Problem kann man beheben, indem
man dem Handler einen Callback zuweist und ihm so eine Methode übergibt,
die eine Funktion als Rückgabewert hat. Dadurch hat man nun die Möglichkeit,
mit Parametern zu arbeiten, wobei in manchen Event-Modellen (z.B. Mozilla
oder Netscape) der erste Parameter standardmäßig für das Event-Objekt
reserviert ist. Es ist nicht relevant, ob die Callback-Funktion anonym oder
benannt ist. Ein Beispiel für solch ein Konstrukt in JavaScript ist folgender
Code:
2
4
6
8
10
12
14
window . o n l o a d = f u n c t i o n ( ) {
document . getElementById ( ” i n f o ” ) . innerHTML = ” ” ;
document . getElementsByTagName ( ” bu tt on ” ) [ 0 ] . o n c l i c k = k l i c k ;
document . getElementsByTagName ( ” bu tt on ” ) [ 1 ] . o n c l i c k = f u n c t i o n ( ) {
klick (1) ;
};
document . getElementsByTagName ( ” bu tt on ” ) [ 2 ] . o n c l i c k = f u n c t i o n ( e v t
) {
document . getElementById ( ” i n f o ” ) . innerHTML = e v t . pageX + ” , ” +
e v t . pageY ;
};
};
function klick (a) {
document . getElementById ( ” i n f o ” ) . innerHTML = a ;
};
Obiges Beispiel ist ein Codeausschnitt. In den Zeilen 3, 4 und 7 wird, wie
es der Standard ist, jedem Event-Handler eine Funktionsreferenz zugewiesen.
Im Beispiel handelt es sich beim auslösenden Event um einen Mausklick auf
einen von drei Buttons. Drückt man den ersten Button, so wird die dritte Zeile
aufgerufen. Zeile 3 ist eine Referenz, die kein Callback ist. Da man dieser Funktionsreferenz aber keine Parameter mitgeben kann, wird nur das auslösende
Objekt als Ausgabe zurückgegeben, in diesem Fall [object MouseEvent].
Wie man dieses Problem beheben kann, zeigt Zeile 4. Statt dem Event-Handler
die Funktion klick direkt zuzuweisen, benutzt man eine Callback-Funktion,
die klick als Rückgabewert hat und diese Funktion (diesmal mit Parameter)
aufruft. Nun wird beim Drücken des zweiten Buttons der Wert zurückgegeben,
dem man klick im Funktionskörper der Callback-Funktion mitgegeben hat.
Zeile 7 zeigt, dass man einem Callback auch direkt einen Parameter (hier evt
genannt) übergeben kann. Wie bereits erwähnt handelt es sich dabei um das
Event-Objekt, also das [object MouseEvent]. Mit den Aufrufen evt.pageX und
evt.pageY erhält man die Koordinatenwerte des Mauszeigers jeweils an dem
7
Punkt, an dem sich die Maus beim Klick auf den dritten Button befindet [13].
Wie das Zusammenspiel zwischen HTML und JavaScript beim Einsatz von
Event-Handlers aussehen kann, wird in folgendem Beispiel aufgezeigt:
HTML:
2
<h1>B i t t e t r e t e n S i e u n s e r e r E−Mail−L i s t e b e i</ h1>
< l a b e l f o r=” e m a i l a d d r e s s ”>E−Mail A d r e s s e :</ l a b e l>
<i n p u t t y p e=” t e x t ” i d=” e m a i l a d d r e s s ” name=” e m a i l a d r e s s ”><br>
4
6
< l a b e l>&nbsp</ l a b e l>
<i n p u t t y p e=” b ut to n ” i d=” j o i n l i s t ” v a l u e=” Tr ete n S i e b e i ! ”><br>
JavaScript:
2
4
6
8
10
12
14
16
// Die $ Funktion
var $ = f u n c t i o n ( id ) {
r e t u r n document . getElementById ( i d ) ;
}
// Der Event−Handler f ü r den K l i c k a u f e i n e n Button
var j o i n L i s t = f u n c t i o n ( ) {
a l e r t ( ” Die j o i n t L i s t −Funktion l ä u f t g e r a d e . ” ) ;
}
// Der Event−Handler f ü r das onchange−E r e i g n i s d e r Textbox
v a r changeValue = f u n c t i o n ( ) {
a l e r t ( ” Die changeValue−Funktion l ä u f t g e r a d e . ” ) ;
}
// Der Event−Handler f ü r das onload−E r e i g n i s , das z w e i Event−Handler
anh ä ngt
window . o n l o a d = f u n c t i o n ( ) {
$ ( ” j o i n l i s t ” ) . o n c l i c k = j o i n L i s t ; //hä ngt 1 . Event−Handler an
$ ( ” e m a i l a d d r e s s ” ) . o n c l i c k = changeValue ; //hä ngt 2 . Event−
Handler an
}
Dieser Code erzeugt eine Textbox, einen Button und zwei Beschriftungen. Es
soll eine Nachricht angezeigt werden, wenn der Button geklickt wird oder wenn
der Benutzer den Wert in der Textbox ändert. In der letzten Methode wird window.unload verwendet. Das heißt, diese Funktion wird erst ausgeführt, nachdem
die Seite komplett geladen und das DOM (Document Object Model) erstellt
wurde. DOM ist eine definierte Norm. Es ist keine eigene Programmiersprache
und ist nicht auf HTML beschränkt. Durch DOM werden Objekte, Eigenschaften und Methoden festgelegt, die eine Programmiersprache umsetzen sollte und
die auf Dokumente anwendbar sind, die auf XML basieren [10].
2.1.3
Weitere Anwendungsgebiete für Callbacks
Ein weiteres Anwendungsgebiet für Callbacks in JavaScript sind TimeoutMethoden. Sie können zum Beispiel wie folgt benutzt werden:
8
1
3
var thePlotThickens = f u n c t i o n ( ) {
c o n s o l e . l o g ( ’ 500ms sp ä t e r . . . ’ ) ;
};
setTimeout ( thePlotThickens , 500) ;
Die Funktion thePlotThickens wird hier nicht sofort ausgeführt, sondern erst
später, wenn sie von setTimeOut aufgerufen wird [11].
Nicht zuletzt wird einem Programmierer durch Callbacks außerdem die
Möglichkeit geboten, asynchron zu arbeiten. Das heißt, während auf eine
Funktion gewartet wird, können zur selben Zeit andere Dinge ausgeführt
werden, was eine erhebliche Zeitersparnis zur Folge hat. Statt zum Beispiel
mit einer while-Schleife oder mit einem Timer zu festgelegten Zeitpunkten den
aktuellen Status abzurufen, kann mit einer Callback-Methode die asynchrone
Operation ohne Unterbrechung durch den aufrufenden Thread (Polling)
ausgeführt werden. Im Folgenden betrachten wir ein Beispiel aus Visual C#,
bei dem es sich um die Implementierung eines Einlesevorgangs handelt, wobei
durch die Callback-Routine die graphische Oberfläche während des Einlesens
einer Datei bedienbar bleibt [4]:
2
4
6
...
p u b l i c p a r t i a l c l a s s Form1 : Form {
// Routine , d i e a u f S t e u e r e l e m e n t e z u g r e i f e n kann :
p u b l i c v o i d FormRefresh ( myState o b j ) {
l i s t B o x 1 . I t e m s . Add( ” C al lB ack : −−− F e r t i g −−−” ) ;
l i s t B o x 1 . I t e m s . Add( ” C al lB ack : G e l e s e n : ” + o b j . B y t e s G e l e s e n .
t o S t r i n g ( ) + ” Bytes ” ) ;
}
8
10
12
14
16
// D e l e g a t e f ü r den A u f r u f d e r Invoke−Methode :
p r i v a t e d e l e g a t e v o i d F o r m R e f r e s h D e l e g a t e ( myState o b j ) ;
// Die H i l f s k l a s s e :
p u b l i c c l a s s myState {
p u b l i c b y t e [ ] Bytes ;
public FileStream f s ;
public i n t BytesGelesen ;
}
18
20
22
24
26
// Die C a l l b a c k −Routine :
public void Fertig ( IAsyncResult asyncResult ) {
// H i l f s o b j e k t e t y p i s i e r e n und verwenden :
myState s t a t e = ( myState ) a s y n c R e s u l t . A s y n c S t a t e ;
s t a t e . B y t e s G e l e s e n = s t a t e . f s . EndRead ( a s y n c R e s u l t ) ;
//Üb e r g a b e von D e l e g a t e und H i l f s o b j e k t :
t h i s . I n v o k e ( new F o r m R e f r e s h D e l e g a t e ( FormRefresh ) , s t a t e ) ;
s t a t e . f s . Close () ;
}
28
// Das S t a r t e n d e s a s y n c h r o n e n D a t e n z u g r i f f s :
9
30
32
34
36
38
40
p r i v a t e v o i d Button1 \ C l i c k ( o b j e c t s e n d e r , EventArgs e ) {
l i s t B o x 1 . I t e m s . Add( ” S t a r t e L e s e v o r g a n g . . . ” ) ;
// H i e r e r z e u g e n w i r u n s e r H i l f s o b j e k t :
myState s t a t e o b j = new myState ( ) ;
// Die e r f o r d e r l i c h e n Daten s p e i c h e r n :
s t a t e o b j . f s = new F i l e t r e a m ( ‘ ‘ 0 1 . j p g ’ ’ , FileMode . Open ,
F i l e A c c e s s . Read , F i l e S h a r e . Read , 1 0 0 0 , t r u e ) ;
s t a t e o b j . Bytes = new b y t e [ s t a t e o b j . f s . Length ] ;
// Asynchronen A u f r u f mit H i l f s o b j e k t a l s Parameter s t a r t e n :
IASyncResult r e s = s t a t e o b j . f s . BeginRead ( s t a t e o b j . Bytes , 0 , (
i n t ) s t a t e o b j . f s . Length , F e r t i g , s t a t e o b j ) ;
}
}
...
Zur Programmierung kann man auf Optimierungen wie zum Beispiel die Entwicklungsumgebungen Node.js, Konzepte zur asynchronen Datenübertragung
wie Ajax (Asynchronous JavaScript and XML) oder auf freie Bibliotheken wie
jQuery zurückgreifen. Hierbei ist anzumerken, dass jQuery unter anderem über
Ajax-Support verfügt, Funktionen zur DOM-Manipulation und -Navigation bereitstellt sowie ein erweitertes Event-System bietet.
2.2
Probleme bei der Verwendung
Werden zu viele Callbacks eingesetzt und hintereinander geschaltet, so wird
der Code schnell unübersichtlich und schwer nachvollziehbar. Teilweise muss
der komplette Code durchgelesen und verstanden werden, um die Aufgabe
einer einzelnen Funktion herauszufinden. In manchen Fällen geht es sogar
so weit, dass es kaum mehr möglich ist, weiteren Code hinzuzufügen, ohne
Fehler bei anderen, eventuell auf den ersten Blick unbeteiligten Funktionen hervorzurufen. Dieses Problem wird als “Callback-Hell” bezeichnet. Als
Beispiel kann folgendes Datei-Auslese-Proramm (JavaScript) verwendet werden:
1
var f s = r e q u i r e ( ” f s ” ) ;
var fileName = ” f oo . tx t ” ;
3
5
7
9
11
13
15
17
f s . e x i s t s ( fileName , f u n c t i o n ( e x i s t s ) {
if ( exists ) {
f s . s t a t ( fileName , f u n c t i o n ( e r r o r , s t a t s ) {
i f ( error ) {
throw e r r o r ;
}
i f ( stats . isFile () ) {
f s . r e a d F i l e ( f i l e N a m e , ” u t f 8 ” , f u n c t i o n ( e r r o r , data ) {
i f ( error ) {
throw e r r o r ;
}
c o n s o l e . l o g ( data ) ;
10
}) ;
}
}) ;
19
21
}
}) ;
Hier sieht man bereits ansatzweise, inwieweit Callbacks in der Anwendung
zu einem großen Problem werden können. Obwohl es nur die drei Funktionen
fs.exists(), fs.stat() und readFile() sind, die hier als Callbacks aufgerufen
werden, wirkt der Code bereits jetzt unübersichtlich und unstrukturiert.
Kommt nun noch komplexerer Code mit weiteren Callback-Funktionen hinzu,
so verliert man in kürzester Zeit den Überblick [9].
Bei Event-Handlers gibt es das allgemeine Problem, dass der mit dem Handler
verknüpfte Code nur ausgeführt werden kann, wenn das visuelle Element
im Browser schon vollständig geladen und die zugehörige Funktion definiert
wurde. Ansonsten wird eine Interaktion des Benutzers mit dem bedienelement
nicht erkannt und die Callback-Funktion, die an den Event-Handler geknüpft
ist, kann nicht aufgerufen werden. Außerdem ist noch nicht standardisiert
festgelegt, welcher Event-Handler in welchem Tag vorkommen darf. Das hat zur
Folge, dass in verschiedenen Browsern die Handler unterschiedlich interpretiert
werden [6]. Als Beispiel ist der JavaScript-Handler onAbort anzuführen. Er
wird für den Fall verwendet, dass ein Benutzer die Anwendung im Browser
schließt, bevor alle Grafiken vollständig geladen wurden. Der Code dazu könnte
beispielsweise so aussehen:
2
4
<html><head>< t i t l e>Test</ t i t l e>
</ head><body>
<img s r c=” o n a b o r t . j p g ” width=” 400 ” h e i g h t=” 600 ” a l t=” G r a f i k ”
o n a b o r t=” a l e r t ( ’ Schade , d a s s S i e das B i l d n i c h t s e h e n w o l l e n . ’ )
”>
</ body></ html>
Dieser Event-Handler kann nur in Microsoft Internet Explorer verwendet werden. Andere Browser wie Opera, Mozilla Firefox oder Safari unterstützen ihn
nicht, weil onAbort nicht zum HTML-Standard gehört.
2.3
Lösungsansätze für auftretende Probleme
Den im vorherigen Kapitel genannten Problemen mit Event-Handlers kann
man begegnen, indem man alle benötigten Funktionen bereits im <HEAD> des
HTML-Dokuments definiert oder aber indem man onload() benutzt. onload()
ist ein Event-Handler, der erst ausgeführt wird, wenn das Dokument vollständig
geladen wurde. Dann erst wird der Zugriff auf die restlichen Event-Handler
gestattet [6].
11
Um die Callback-Hell zu vermeiden, können ebenfalls ein paar einfache,
präventive Maßnahmen ergriffen werden. Diese bestehen beispielsweise darin,
den Code ausreichend zu kommentieren, nicht zu viele Callbacks hintereinander
zu schalten und kurze Namen für die Callback-Funktionen zu wählen. Das
reicht aber in vielen Fällen nicht aus, denn oft hat man bei sehr umfangreichem
und komplexem Code keine andere Wahl und die Konstrukte kaskadieren.
Deshalb sollte über den Einsatz von Functional Reactive Programming (FRP)
nachgedacht werden.
FRP ist ein Framework zur Beschreibung von zeitabhängigen Relationen. Es
lässt asynchrone Funktionsaufrufe ohne die Verwendung von Callbacks zu und
ist so konzipiert, dass dabei die Syntax und Semantik des Codes lesbar und
leicht nachvollziehbar bleibt [7].
Zur Programmierung stehen Stream-Funktionen wie map, filter, scan, oder
merge zur Verfügung, durch die man auf Kontrollflusselemente wie if, for oder
while verzichten kann. Statt einer Sequenz von hintereinander geschalteten
Anweisungen, die nacheinander abgearbeitet werden, werden dem Computer
nur die Beziehungen zwischen Streams mitgeteilt. Das alles führt dazu, dass
Konstrukte wie Callbacks, die letztendlich in Problemen wie der Callback-Hell
resultieren könnten, vollkommen überflüssig werden. Die Implementierung
erfolgt durch Programmiersprachen wie zum Beispiel Haskell oder Elm.
Insbesondere Elm ist auf die Kompilierung von JavaScript, HTML und
CSS (Cascading Style Sheet) sowie auf die Vereinfachung von GUIImplementierungen ausgelegt. Durch zeitabhängige Variablen, die Input
oder Output repräsentieren können, wird dem Programmierer die Möglichkeit
gegeben, komplexe Zusammenhänge reaktiv und deklarativ zu implementieren [3].
In den folgenden zwei Codebeispielen wird der Unterschied zwischen JavaScriptCallbacks und Elm klarer. In ihnen geht es jeweils um den Zugriff auf die
aktuellen Position der Maus:
JavaScript:
2
4
$ ( document ) . r e a d y ( f u n c t i o n ( ) {
var p o s i t i o n = { ’ x ’ : 0 , ’ y ’ : 0 } ;
$ ( document ) . bind ( ’ mousemove ’ , f u n c t i o n ( e v e t ) {
p o s i t i o n = { ’ x ’ : e v e n t . pageX , ’ y ’ : e v e n t . pageY } ;
}) ;
6
8
10
setInterval ( function () {
// custom p o s i t i o n code
} , seconds ∗ 1000) ;
}) ;
12
Elm:
im po rt Mouse
2
main = l i f t asText Mouse . p o s i t i o n
Hier sieht man den Unterschied zwischen den Codefragmenten deutlich. Für
die gleiche Aktion hat Elm einen sehr viel einfacheren Implementierungsansatz
als JavaScript. Es muss nicht auf Callbacks zurückgegriffen werden. Stattdessen
wird ein Signal (hier die Position der Maus) zu einem Text konvertiert und
durch lift aktualisiert, sobald sich der Wert ändert (hier also wenn die Maus
bewegt wird). Dieses simple Beispiel zeigt bereits, welche Möglichkeiten einem
Programmierer durch Funktional Reaktive Programmierung geboten werden.
Sogar das Problem der Callback-Hell kann durch Sprachen wie Elm in einfachen,
nachvollziehbaren Code umgewandelt werden.
Elm versucht, dem Programmierer gleichzeitig Flexibilität und Expressivitt zu
bieten, wobei es gleichzeitig nur auf Abstraktionen zurückgreift, die effizient in
einem nichtsequentiellen System implementiert werden können [14].
3
Pro und Contra der Anwendung
Callbacks und Event Handlers sind mächtige Instrumente, die vor allem bei
der webspezifischen Programmierung eine sehr große Rolle spielen. Durch sie
wird die Kommunikation zwischen Server und Client vereinfacht und effizienter
gestaltet. Sie sind die Schnittstelle zwischen User und Skript und verhelfen zu
mehr Benutzerfreundlichkeit im Bezug auf die Bedienoberfläche. Wie man sie
einsetzt ist schnell gelernt und eingängig. Wie in Kapitel 2.1 schon erwähnt,
kann es aber leider zu Problemen kommen, v.a. im Bezug auf die CallbackHell. Deswegen wäre es sinnvoll, Callbacks und Event-Handlers nur bei kurzem
oder wenig verschachteltem Code zu verwenden, damit die Nachvollziehbarkeit
bestehen bleibt. Als Alternative kann für komplexeren Code Functional Reactive
Programming eingesetzt werden. Vor Allem bei webspezifischen Anwendungen
hat sich das jedoch noch nicht durchgesetzt.
Callbacks und Event-Handlers sind beliebte und verbreitete Strukturmittel, die
ihre Nützlichkeit durch ihre vielfältigen Einsatzmöglichkeiten und -gebiete unter
Beweis stellen. Ob sie sich auch in Zukunft durchsetzen können oder ob sie durch
übersichtliche, aber schwer zu implementierende Konstrukte aus der Funktional
Reaktiven Programmierung ersetzt werden, wird sich erst noch zeigen.
13
Literatur
[1] Communications of the ACM, 51(1), 2008.
[2] Dave Crane, Bear Bibeault, and Jord Sonneveld. Ajax in practice - Das
Praxisbuch für die Web 2.0-Entwicklung. Addison-Wesley Verlag, 2008.
[3] Evan Czaplicki and Stephen Chong. Asynchronous Functional Reactive
Programming for GUIs. Technical report, Harvard University, 2013.
[4] Walter Doberenz and Thomas Gewinnus. Visual C# 2010 - Grundlagen
und Profiwissen. Carl Hanser Verlag München, 2010.
[5] Conal Elliott. Push-pull functional reactive programming. In Haskell Symposium, 2009.
[6] David Flanagan. JavaScript: Das umfassende Referenzwerk. O’Reilly Verlag, 1997.
[7] M. Hagiya and P. Wadler. Functional and Logic Programming: 8th International Symposium, FLOPS 2006, Fuji-Susono, Japan, April 24-26, 2006,
Proceedings. Lecture Notes in Computer Science / Programming and Software Engineering. Springer, 2006.
[8] Tom Hughes-Croucher and Mike Wilson. Einführung in Node.js. O’Reilly
Verlag, 2012.
[9] C.J. Ihrig. Pro Node.js for Developers. Expert’s voice in Web development.
Apress, 2013.
[10] Zak Ruvalcaba and Mike Murach. Murachs JavaScript and jQuery. Mike
Murach & Associates, Inc., 2012.
[11] S. Stefanov. JavaScript Patterns. O’Reilly Verlag, 2011.
[12] Ralph Steyer. jQuery - DasJavaScript-Framework für interaktives Design.
Addison-Wesley Verlag, 2011.
[13] Ralph Steyer. JavaScript für Fortgeschrittene - Debugging, PerformanceTsools, OOP. Video-Training, online, 2013.
[14] Bruce Tate, Fred Daoud, Jack Moffitt, and Ian Dees. Seven More Languages
in Seven Weeks: Languages That Are Shaping the Future. The Pragmatic
Bookshelf, 2014.
14
Herunterladen