Arkiv för oktober, 2009

JSON och MooTools för Web Workers

MooTools är en trevlig verktygslåda som främst är tänkt för att skriva JavaScript-kod som manipulerar element på en webbsida och skapar animeringar och grafiska effekter. Därför är den starkt knuten till objekten window och document som finns i det globala kontextet när JavaScript-kod körs på en vanlig webbsida.

MooTools i Worker-kontext

Men MooTools har även hjälpmedel för att skriva objektorienterad kod samt en del utökningar och förbättringar för språket som sådant. Om man vill dra nytta av detta för kod som körs i ett annat sammanhang där window och document inte finns tillgängliga, t.ex. i en Web Worker tråd, vad gör man för att få mootools att fungera då?
En variant är att skapa mock-up objekt för att maskera det faktum att objekten inte finns, tomma skelett som bara innehåller det nödvändigaste för att mootools skall kunna laddas utan fel. Självklart ger inte detta tillgång till någon funktionalitet som är beroende av dessa objekt men övriga funktioner finns på plats.

// If we're in a worker we need to masquerade the global context and load mootools
if (self.importScripts) {
	document = {
		prototype: function() {},
		createElement: function() {},
		getElementsByTagName: function() {return []}
	};
	window = {
		document: document,
		Document: document,
		Element: { prototype: function() {} },
		Window:  { prototype: function() {} },
		addEventListener: function() {},
		attachEvent: function() {},
	};
	self.importScripts('mootools.js');
}

Skicka objekt till Workers

Eftersom Web Workers är helt isolerade från webbsidan, dvs. inte har tillgång till något delat minne, går det inte att skicka objekt till dem hur som helst. Enda sättet att kommunicera är genom att posta meddelanden som bara kan överföra strängar. Självklart kan man då serialisera objekten till JSON och skicka med dem.

Varför heter det JSON?

Vad jag då skulle vilja reflektera över är varför det kallas JavaScript Object Notation. Ett objekt är ju en sak som vet vad den är och kan göra saker själv, dvs. en datastruktur med tillhörande kod som beskriver hur den skall uppföra sig.
När man serialiserar ett objekt till en JSON-sträng försvinner alla kodreferenser, dvs. objektets metoder, kvar har man bara datastrukturen. Därför kan det tyckas vara mer korrekt att det borde kallas JavaScript Data Notation

Välsigna datastrukturer

Vad gör vi då för att kunna använda datastrukturer som blivit deserialiserade från JSON som fullfjädrade objekt? Vi kan välsigna dem tillbaka till sin klasstillhörighet genom att koppla ihop datastrukturen med metoderna från klassen igen. Därför skapar vi en en konstruktor som heter bless i basklassen för alla klasser Class som tar en datastruktur och utökar en ny instans av klassen med denna.

// Contructor that returns a new instance of this class
// extended with all properties of the given data structure
Class.prototype.bless = function(data) {
	return $extend(new this(), data);
};

Då kan vi sedan göra exempelvis så här:

var MyClass = new Class({
	myData: "Hello, world!",
	doStuff: function() {
		alert(this.myData);
	}
});
 
var myObject = new MyClass();
var string = JSON.encode(myObject);
 
var data = JSON.decode(string);
// data.doStuff();  <--- Not possible here
var newObject = MyClass.bless(data);
newObject.doStuff();

På så vis kan man återskapa objekt som är identiska med de som skickades trots att de har blivit omvandlade till och från en ren textsträng på vägen.

Så får du Google Sync att fungera med din iPhone

För några månader sedan flyttade vi över epost, kalendrar, kontakter och en hel del annat till Google Apps. Det kan jag verkligen rekommendera, men det är inte det vi ska prata om idag. För några dagar sedan fick Athega äntligen leveransen av alla iPhone 3GS-telefoner. Detta aktualiserade hur vi skulle få just epost, kalendrar och kontakter att synkroniseras mellan mobil, dator och Google.

Visst, man kan hävda att Googles iPhone-anpassade Safari-applikationer är bra nog och ibland bättre, men den här guiden visar hur du får epost, kalendrar och kontakter till de nativa motsvarigheterna i din iPhone.

Viktigt att tänka på innan du börjar är att Google endast tillåter ett konto av detta slag (jag har exempelvis lagt till min privata gmail via vanlig IMAP).

Aktivera Google Sync för Google Apps

För att synkroniseringen ska fungera fullt ut behöver du eller din Google Apps-administratör aktivera Google Sync. Detta görs genom att kryssa för ”Aktivera Google Sync” under ”Inställningar för mobilen” när du befinner dig på Tjänstinställningar för Google Apps som administratör.
Inställningar för mobilen

Välj kalendrar

Om du inte aktivt väljer vilka kalendrar du vill synkronisera, kommer du bara få din standardkalender. Detta kanske räcker för en del, men jag har flera olika kalendrar som jag vill få synkroniserade. Att få detta att fungera var inte helt problemfritt. Google kommer säkert förbättra detta, men när detta skrivs behöver du göra enligt nedan.

Svenska stöds inte

Svenska stöds inte

Nu visas Sync-ikonen

Nu visas Sync-ikonen

Din iPhone

Din iPhone

Se till att du är inloggad med ditt Google Apps-konto och att m.google.com är konfigurerad till din domän. Tyvärr såg jag ingen Sync-ikon, efter detta. Det visade sig att jag var tvungen att ändra språk långst ner på sidan. Efter jag ändrat till ”English (US)” och även land till ”USA”, visades ikonen som den skulle.

Nästa steg är att välja din iPhone och sedan vilka kalendrar du vill synkronisera.

Välj kalendrar

Välj kalendrar

Sätt upp ett Exchange-konto

Detta gör du genom att välja Inställningar -> E-post, kontakter, kalendrar -> Lägg till konto… De inställningar du behöver hittar du här.

Sätt upp ett Exchange-konto

Om du har befintliga kalendrar får du välja om du vill ersätta dem. I mitt fall ville jag det eftersom de kalendrar som redan fanns i min iPhone var samma Google-kalendrar, synkroniserade via iTunes.

Radera eller spara befintliga kalendrar?

Radera eller spara befintliga kalendrar?

Så var det klart, alltid samma data i din iPhone som på Google Apps och med Push!

Fördjupning

Mer information hittar du hos Google:

JavaScriptprestanda

För moderna webbapplikationer där en större del av koden körs i webbläsaren blir det allt viktigare med bra prestanda för exekvering av JavaScript.
För att kontrollera text i formulärfält och liknande simpla uppgifter är inte hastigheten så avgörande, men vad händer om man försöker köra tyngre beräkningar? För att göra ett benchmark som testar prestandan i de vanligaste webbläsarna har jag skrivit ett program som löser Sudokus.

Ett program som löser Sudoku med JavaScript

För att jämföra de olika webbläsarna har jag kört denna Sudoku-kombination och jämfört tiden det tar att räkna fram alla möjliga lösningar på just min dator. Resultatet är ganska häpnadsväckande, som ni kan se i grafen nedan så utklassar Safari Internet Explorer med nästan en faktor på tio-till-ett. Chrome hamnar inte långt efter och både Firefox och Opera placerar sig hyffsat bra. Och då används inte ens Web Worker-trådar som har visat sig ha potential att dubbla prestandan och ytterligare öka försprånget för alla andra webbläsare framför Internet Explorer.

Tid för att lösa ett Sudoku med JavaScript i olika webbläsare