Martin Lantzsch
Software Entwickler
30. September 2013

Einen JavaScript Array erkennen

30. September 2013 - Geschrieben von Martin - Keine Kommentare

Gerade habe ich beim Code Review folgenden Code gesehen:

typeof [1, 2, 3] === 'array'

Von der Logik her okay, aber halt! Ein JavaScript Array ist doch ein Objekt? Und ja ein schneller Hack auf der Konsole sagt uns

typeof [1, 2, 3]
=> "object"

Ergo müssen wir prüfen ob das Objekt eine Instanz von Array ist

[1, 2, 3] instanceof Array
=> true

29. August 2013

ExtJS Store AJAX Proxy HTTP Basic Authorization

29. August 2013 - Geschrieben von Martin - Keine Kommentare

Um Daten von einem Webservice abzurufen, der mittels HTTP Basic Authorization gesichert ist muss dem AJAX Proxy ein Header mitgegeben werden, der die Base64 encodeten Zugangsdaten enthält. Dies habe ich bei meinem Store direkt in den Konstruktor geschrieben:

constructor: function(config) {
    this.proxy.headers = {
        'Authorization': 'Basic ' + window.btoa(config.username + ':' + config.password)
    };
    this.callParent(config);
}

im Gesamten dann etwa so:

Ext.define('Resi.stores.Mails', {
    proxy: {
        type: 'ajax',
        url: 'api/mails'
    },
    constructor: function(config) {
        this.proxy.headers = {
            'Authorization': 'Basic ' + window.btoa(config.username + ':' + config.password)
        };
        this.callParent(config);
    }
});

Die verwendete window.btoa ist leider nur in neuen Browsern verfügbar, sollten auch ältere Browser später diese Anwendung nutzen sollen, muss hier eine Base64 Bibliothek eingebunden werden.

var Mails = Ext.create('Resi.stores.Mails', { 
    username: 'Resi',
    password: 'Mein sicheres Passwort'
});

6. Januar 2013

NodeJS MySQL pool

6. Januar 2013 - Geschrieben von Martin - 2 Kommentare

Momentan arbeite ich daran Resigame 2.0 auf NodeJS Basis zu entwickeln. Da abzusehen ist, dass auf Resigame wieder sehr hoher Traffic entstehen wird, wird das ganze Performance optimiert entwickelt. Cluster, SQL Pooling, etc.

Gestern habe ich mir ein Modul für den MySQL Pool geschrieben, denn bei vielen NodeJS Applikationen wird entweder für jeden HTTP Request eine MySQL Verbindung verwendet oder eine für alle.

Das Problem bei einer Verbindung pro HTTP Request ist, dass die Verbindungen bei hohen Nutzerzahlen sehr schnell ausgehen (MySQL max connections) und man ggf. ein paar Sekunden auf die nächste freie Verbindung warten muss.

Bei der Methode mit einer Verbindung, die für alle Nutzer verwendet wird, ist natürlich die Performance sehr bescheiden. Aufwändige Querys können die ganze Applikation stark ausbremsen.

Also habe ich einen MySQL Pool entwickelt, dieser wird beim starten der Anwendung erzeugt. Man übergibt die „poolsize“ – also die Anzahl der Verbindungen die hergestellt werden sollen (diese muss natürlich unter der maximalen Anzahl an Verbindungen, die der MySQL Server zulässt liegen) und die Zugangsdaten zum Datenbankserver. z.B.

var pool = new require('/helpers/pool')({
	poolsize: 50,
	mysql: {
		host: 'localhost',
		user: 'root',
		password: 'root',
		database: 'resigame'
	}
});

Querys können nun direkt an den Pool gesendet werden:

pool.query('SELECT * FROM users WHERE userID = ?', [userID], function(err, results) {
	// whatever
});

Der Aufruf fügt den Query zur Warteschlange hinzu und sieht nach ob gerade eine Verbindung frei ist. Wenn ja wird diese gleich verwendet, ansonsten dauert es bis wieder eine Verbindung frei wird. (Ergo, je mehr Benutzer die gleichzeitig auf die Datenbank zugreifen, desto höher die poolsize –> mehr Performance).

Hier der Quellcode, ich werde ihn die Tage noch ein wenig erweitern und dann auf GitHub stellen.

/** 
 * MySQL pool to hold multiple connections to the database server
 *
 * @author	Martin Lantzsch <martin@linux-doku.de>
 */
 
var mysql = require('mysql');
module.exports = function(config) {
	this.freeConnections = [];
	this.queryQueue = [];
 
	this.createConnection = function(details) {
		var connection = mysql.createConnection(details);
		connection.connect();
		connection.number = this.freeConnections.length;
		this.freeConnections.push(connection);
	};
 
	this.query = function(command, params, callback) {
		if(typeof(params) == 'function') {
			callback = params;
			params = [];
		}
 
		this.queryQueue.push({
			command: command,
			params: params,
			callback: callback
		});
		this.work();
	};
 
	this.work = function() {
		var self = this;
		if(self.queryQueue.length > 0) {
			if(self.freeConnections.length > 0) {
				var query = self.queryQueue.shift();
				var connection = self.freeConnections.shift();
				connection.query(query.command, query.params, function(err, results) {
					if(err) throw err;
					query.callback(err, results);
					self.freeConnections.push(connection);
					if(self.queryQueue.length > 0)
						self.work();
				});
			}
		}
	};
 
	for(i = 0; i < config.poolsize; i++) {
		this.createConnection(config.mysql);
	}
 
	return this;
}

20. November 2012

jQuery click nicht auf Childs anwenden

20. November 2012 - Geschrieben von Martin - Ein Kommentar

Wenn man mit jQuery einen Klick Event Handler auf ein Element setzt, so wird dieser auch automatisch bei klick auf ein Kindelement ausgeführt.

Um das zu umgehen, habe ich mir folgende if Abfrage mit eingebaut, die prüft ob das geklickte Element auch wirklich das Element ist, dass im Event Handler angegeben wurde und keines der Kind Elemente.

$('.element').click(function(data, handler) {
	if(data.target == this) {
		// Code
	}
});

17. August 2012

Firefox Hack – onresize page refresh

17. August 2012 - Geschrieben von Martin - Keine Kommentare

Die Entwickler von Firefox meinen es sei nicht nötig, dass man beim resizen des Fensters die Seite neu lädt und haben so bei der Behandlung des Resize Events jegliche Seiten reloads gesperrt.

Da ich das allerdings in einem bestimmten Anwendungsszenario trotzdem benötigte, habe ich herausgefunden, dass man es mit folgendem „Hack“ umgehen kann, weil der Reload dann natürlich nicht mehr vom resize initiiert wird:

$(window).resize(function() {
	setTimeout(function() { window.location.reload() }, 0);
});

Durch den Timeout mit der Verzögerung von 0 Millisekunden (also sofort) wird die aufgerufene Funktion sozusagen in ihrer Herkunft anonymisiert.

Sehr umständlich, in allen anderen Browsern funktioniert es direkt, aber die Saboteure von Mozilla meinten wieder sie müssen die Welt verbessern…

23. Mai 2012

jQuery Easypassgen für Fomulare

23. Mai 2012 - Geschrieben von Martin - Keine Kommentare

Ich habe eine Modifikation an dem jQuery Plugin easypassgen vorgenommen um Passwörter auch in Formularfelder schreiben zu können. Es wird nun geprüft ob ein Attribut namens „value“ existiert, wenn ja wird das Passwort dort hineingeschrieben.

/* http://code.google.com/p/jquery-easypassgen/
   Easy Password Generator for jQuery v1.4.
   Written by Yuri Pikin (me{at}jurius.name) December 2010.
   Licensed under the MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) license.
   Please feel free to use it.
 
   Example page enable at http://pasw.pm-tools.ru
*/
 
(function( $ ){
 
    var methods = {
        init:   function ( options ){
 
            return this.each(function( ){
 
                var $this = $(this);
 
		if($this.attr('value') == undefined) {
			$this.html($.fn.easypassgen('generate', options ));
		} else {
			$this.attr('value', $.fn.easypassgen('generate', options ));
		}
            });
        },
        generate: function( settings ){
 
            var system = {
                commonChars:    "bcdfghkmnprstvz",
                allConsonants:  "bcdfghkmnprstvzjqwx",
                allVowels:      "aeuy",
                allChars:       "bcdfghkmnprstvzjqwxaeuy",
                specialChars:   "#^:_-",
                randomize:      function( from, to){
                    from = typeof(from) != 'undefined' ? from : 0;
                    to = typeof(to) != 'undefined' ? to : from + 1;	
                    return Math.round(from + Math.random()*(to - from));
                },
                getRandomCharacter: function(a){
                    return a.charAt(this.randomize(0,a.length-1));
                }
            };
 
            var defaultSettings = {
                'syllables':        3,
                'numbers':          true,
                'specialchars':     false
            };
 
            if (settings){
                $.extend( defaultSettings, settings );
            }
 
            var numberProbability = 0, numberProbabilityStep = 0.25;
            var specialProbability = 0, specialProbabilityStep = 0.5;
 
            var generatedPass = '';
 
            for(var i = 0; i < defaultSettings.syllables; ++i) {
                    if(Math.round(Math.random())) {
                            generatedPass += system.getRandomCharacter(system.commonChars).toUpperCase() +
                                                                    system.getRandomCharacter(system.allVowels) +
                                                                    system.getRandomCharacter(system.allChars);
                    } else {
                            generatedPass += system.getRandomCharacter(system.allVowels).toUpperCase() +
                                                                    system.getRandomCharacter(system.commonChars);
                    }
                    if(defaultSettings.numbers && Math.round(Math.random() + numberProbability) && ( i != (defaultSettings.syllables-1))) {
                            generatedPass += system.randomize(0,9);
                            numberProbability += numberProbabilityStep;
                    } else if (defaultSettings.specialchars && Math.round(Math.random() + specialProbability) && (i != (defaultSettings.syllables-1))){
                            generatedPass += system.getRandomCharacter(system.specialChars);
                            specialProbabilityStep += specialProbabilityStep;
                    }
            }
 
            return generatedPass;
        }
    }
 
    $.fn.easypassgen = function( method ) {
 
        if ( methods[method] ) {
            return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.easypassgen' );
        }
    };
 
})( jQuery );

11. Oktober 2011

Excel ausgestiegen

11. Oktober 2011 - Geschrieben von Martin - Keine Kommentare


Ops, da war mein VBA (Visual Basic for Applications ;)) Script wohl zu komplex. Excel Tabelle in XML Exportiert, das Script auf JavaScript portiert und schwups war mein Ergebnis auf dem Schirm :)

23. Dezember 2010

Chrome von Surfern für Surfer

23. Dezember 2010 - Geschrieben von Martin - 2 Kommentare

Google Chrome wird zwar oft als Datenkrake niedergemacht, ist meiner Meinung nach aber einer der besten Webbrowser. Er bietet alle Features, die man zum Surfen im Web braucht und nicht nur das, alles ist an der richtigen Stelle. Es gibt keine überladenen Menüs, keine Platzverwenderischen Favoriten Leisten… Nichts, und das ist gerade das tolle an Chrome. Man könnte fast meinen der Browser passt sich an einen an, so einfach und schnell geht das surfen mit ihm von der Hand. Fast schon unheimlich.


Erweiterungen? Gibt es tausende, aber ich mache nur von wenigen Gebrauch. Und das beste? Ganz klar, sie fügen sich schön neben dem Menü ein und so geht kein Wertvoller Platz verloren. Klar, das viele Erweiterungen nicht so toll aussehen nervt mich schon ein wenig aber dafür ist es ganz leicht neue zu erstellen, da es sich nur um JavaScript handelt :)


Eigentlich gibt es zu Chrome nicht viel zu sagen, denn wie schon dargelegt es gibt nicht sonderlich viel. Wobei, die Entwickler Tools möchte ich nicht unerwähnt lassen. Vom Element Browser, über Ladezeit Anzeigen bis hin zum JavaScript Debugger alles an Board. Selbst in einem neuen Fenster kann man ihn öffnen, spätestens jetzt sollten Dual oder sogar Tripple Head Besitzer Hellhörig werden.

Da bliebe nur noch die Sache mit der Datenkrake, was will man machen und Hey! Wie viele von euch sind mit eingeloggtem Facebook Account unterwegs ;-) (Für alle Unwissenden: Facebook loggt die von euch besuchten Seiten mit, die Facebook Connect einsetzen).

Ach übrigens, frohes und gesegnetes Fest euch allen.