Een introductie tot Node.js

In deze tutorial ga ik het hebben over Node.js. In de toekomst mag je je zeker aan meerdere Node.js tutorials verwachten die allerlei mogelijkheden van dit platform zullen illustreren.

Wat is Node.js

Node.js is een platform dat gebaseerd is op de V8 JavaScript engine van Google (wordt gebruikt in Google Chrome). Iedereen kent JavaScript wel denk ik, een scripting-taal die gebruikt wordt om interactieve websites te maken. Wat de V8 engine doet is eigenlijk machine-code genereren uit JavaScript code waardoor je dus applicaties kan bouwen met deze engine.
Node.js maakt dus gebruik van deze V8 engine en heeft enkele extra’s toegevoegd in C++.

Node.js is eigenlijk een back-end variant van de JavaScript die wij kennen (voor front-end development van websites). Dit platform zorgt voor snelle I/O events zoals web calls, netwerk communicatie, files, … .  We weten dus dat Node.js bestaat uit een hoop JavaScript en C++ en dat gebruikt voor I/O, maar we weten nog niet wat juist de kracht is achter Node.js of waarom het ervoor zorgt dat het zo snel is.

JavaScript is een heel eenvoudige taal om te leren en wordt naast DOM manipulatie ook gebruikt voor iets dat we “AJAX” of Asynchronous JavaScript and XML. Wat je hier uit moet onthouden is het “Asynchronous” gedeelte. In JavaScript wordt er namelijk vaak gebruik gemaakt van callbacks die aangeroepen worden nadat er iets gebeurd is (bijvoorbeeld een response gekregen via AJAX).
Dankzij deze aanpak hangt niet de hele website vast als je AJAX gebruikt, de CPU kan immers andere taken verrichten terwijl de AJAX request verstuurd is. Dit is in contrast met een synchrone applicatie waar alles achter elkaar uitgevoerd wordt. De CPU moet telkens wachten totdat een actie verricht is voordat hij verder kan om het programma uit te voeren.

Genoeg over JavaScript nu (voor even toch), waarom is C++ nu eigenlijk zo goed. Gamers weten dat de meeste games geschreven zijn in C++ omdat het een low-level taal is die veel minder overhead heeft en meer in eigen hand legt (zaken zoals garbage colleciton) waardoor het ook veel beter geoptimaliseerd kan worden.
De combinatie van C++ en JavaScript zorgt er dus voor dat we een heel snel platform hebben dat asynchrone calls kan verrichten.

Node.js downloaden

Node.js kan je downloaden van nodejs.org. De install knop zou er voor moeten zorgen dat je de juiste installer binnen krijgt. Je zou ook zelf de source kunnen compilen maar dat ga ik achterwege laten in deze tutorial.

Als alles gedownload en geïnstalleerd is kan je controleren of alles in orde is door een command prompt/terminal te openen en het commando

node --version

in te voeren. Indien je een resultaat als in onderstaande afbeelding krijgt dan is alles goed gegaan.

Ready? Set… Go!

Zoals ik eerder al zei is Node.js goed vanwege z’n snelheid. In plaats van dat jullie me maar moeten geloven met wat ik zeg, zal ik ook illustreren dat dit klopt door een applicatie te schrijven die het aantal priemgetallen onder 1 miljoen, 10 miljoen en 100 miljoen bepaalt en dat in zowel PHP, Java en JavaScript (met Node.js).

De code (in JavaScript):

function getPrimes(number) {
    var counter = 0;
    for (var i = 0;i <= number;i++) {
        if (isPrime(i)) {
            counter++;
        }
    }
    return counter;
}

function isPrime(number) {
    if (number == 2) {
        return true;
    }
    var j = Math.sqrt(number);
    var isPrime = true;
    for (var i = 2;i <= j && isPrime;i++) {
        isPrime = (number % i != 0);
    }
    return isPrime;
}

var d = Date.now();
console.log(getPrimes(100000000));
console.log(Date.now() - d);

De code in PHP:

<?php
function getPrimes($number) {
    $counter = 0;
    for ($i = 0;$i <= $number;$i++) {
        if (isPrime($i)) {
            $counter++;
        }
    }
    return $counter;
}

function isPrime($number) {
    if ($number == 2) {
        return true;
    }
    $j = sqrt($number);
    $isPrime = true;
    for ($i = 2;$i <= $j && $isPrime;$i++) {
        $isPrime = ($number % $i != 0);
    }
    return $isPrime;
}

$start = microtime(true);
echo getPrimes(1000000) ."\r\n";
echo round((microtime(true) - $start) * 1000) ."\r\n";

?>

En als laatste ook nog eens de code in Java:

package be.g00glen00b.examples;

public class CalculatePrimes {

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        System.out.println(getPrimes(100000000));
        System.out.println(System.currentTimeMillis() - start);

    }

    public static int getPrimes(int number) {
        int counter = 0;
        for (int i = 0;i <= number;i++) {
            if (isPrime(i)) {
                counter++;
            }
        }
        return counter;
    }

    public static boolean isPrime(int number) {
        if (number == 2) {
            return true;
        }
        int max = (int) Math.sqrt(number);
        boolean isPrime = true;
        for (int i = 2;i <= max && isPrime;i++) {
            isPrime = (number % i != 0);
        }
        return isPrime;
    }

}

Ik heb dit enkele keren laten runnen en dit waren mijn resultaten.

#PHPNode.jsJava
1.000.00046653 ms760 ms340 ms
10.000.00019406 ms8424 ms
100.000.000747847 ms459907 ms

Zoals je kan zien loopt PHP enorm achter ten opzichte van Java en Node.js. Java is sneller dan Node.js in dit voorbeeld, maar in dit voorbeeld laten we Node.js via één core werken terwijl Java meerdere cores kan gebruiken. Des ondanks is het verschil tussen Node.js en Java (relatief gezien) wel kleiner geworden na 100.000.000 bewerkingen. Als je eenzelfde voorbeeld wilt zien waarbij Node.js meerdere cores gebruikt, kijk dan ook zeker even naar deze tutorial.

Hello worl… webserver?

Als tweede voorbeeld ga ik een Hello world variant laten zien voor Node.js, maar in plaats van dat ik een gewoon console-programma ga schrijven, ga ik er een webserver van maken.

Node.js werkt modulair, dit wilt zeggen dat de code verspreid staat over verschillende modules en dat je dus eigenlijk standaard enkel met de basistools kan werken. Modules importeer je met de

require()

functie. In dit voorbeeld gaan we de module http gebruiken.

Node.js werkt met callbacks en events, voor beide kan je een functie gaan schrijven maar zoals in JavaScript kan je dit gemakkelijk doen met anonymous functions. Het voordeel hiervan is dat je minder schrijfwerk hebt, maar hoe meer code je schrijft, des te complexer de code zal worden.

In dit voorbeeld ga ik wel met anonymous functions werken, de code voor dit voorbeeld is:

var http = require('http');

http.createServer(
    function(request, response) {
        request.on("end", function() {
            response.end("Hello world, Node.js");
        });
    }
).listen(8080);

Zoals je kan zien importeren we eerst de HTTP module. Deze returnt een object dat we kunnen gebruiken om een server mee te creëeren. Bij elke HTTP request zal deze een ServerRequest en ServerResponse object geven die je kan gebruiken om de data van de request op te vragen en een response te genereren.

Hier gaan we ook gebruik maken van het end-event. Events kan je oproepen door de

on()

functie die de naam van het event en een callback accepteert als parameters.

Hier kunnen we de response wijzigen en naar de client (= web browser) sturen.

Als we nu de code opslaan als een bestand met de JS-extensie (bijvoorbeeld

hello-world.js

) dan kan je de code runnen met het commando

node hello-world.js

.
Als je dan je browser opent en navigeert naar http://localhost:8080 dan krijg je hetzelfde resultaat als hieronder.

Pros & cons

We hebben nu hopelijk een iets duidelijker beeld van wat Node.js is en niet is, wat het kan en niet kan. Even ga ik nog enkele voordelen en nadelen opsommen.

Voordelen:

  • JavaScript is een bekende taal, de userbase is dus redelijk groot
  • Node.js kan enorm snel I/O events behandelen
  • Node.js kan asynchroon werken door gebruik van callbacks
  • JavaScript is een eenvoudige taal om te leren en dus de leercurve voor de taal op zich is vrij klein.

Enkele nadelen:

  • Alhoewel dat JavaScript bekend is, is Node.js dat niet, het zal er dus vaak op aankomen dat je zelf dingen moet oplossen.
  •  Node.js is op het moment van schrijven nog maar aan v0.8.8, de technologie op zich is dus nog niet volgroeid en moet nog maturiseren.
  • De documentatie is zeer moeilijk om te doorgronden en is vaak ook inconsistent.
  • JavaScript is eenvoudig, maar door het gebruik van anonymous functions in callbacks en events kan je code er snel slordig uitzien.

TL;DR

Je vraagt je nu misschien af waar je Node.js voor kan gebruiken. Het succes van Node.js ligt vooral achter de snelheid en het asynchroon kunnen werken. Kort samengevat is het dus een platform dat handig is bij applicaties die een hoge concurrency hebben zoals webservices.

Download project

Download – node.js.rar (2,2 kB)

Tagged , , .

g00glen00b

Consultant at Cronos and Tech lead at Aquafin. Usually you can find me trying out new libraries and technologies. Loves both Java and JavaScript.

  • Tom P

    leuke code, maar 1 klein bugje …
    hij telt getal 0 ook als priemgetal, dus:

    function getPrimes(number) {
    var counter = 0;
    for (var i = 1;i <= number;i++) { // ipv. var i = 0; …

  • Deze post is al een tijdje geleden, maar toch even een opmerking over de performance test die je verricht hebt.
    ( correct me if I’m wrong ).
    Java gebruikt niet zomaar meerdere cores, die moet je ook daadwerkelijk aanspreken. Bijvoorbeeld door gebruik te maken van Runnable: CalculatePrimes implements Runnable etc.
    Dat staat hier: http://www.javabeginner.com/learn-java/java-threads-tutorial vrij goed uitgelegd. Je kan bijvoorbeeld elke thread, een ander getal mee te geven en te beoordelen.

    Anyway, ik wou even zeggen dat de snelheid niet simpelweg te verklaren is doordat Java gebruik kan maken van meerdere Threads – of zoals jij zei, “meerdere cores” – Het is ook niet zo dat Javascript niet op multiple-cores kan draaien google daar maar op, en ook nodejs kan op meerdere cores draaien door te forken, lees: http://nodejs.org/about/ Dan zoekt je OS zelf uit op welke core het andere proces moet draaien..
    Gelukkig doet nodejs niet aan threads maar is event-driven, heel relaxed in javascript natuurlijk omdat je heel makkelijk functie pointers kan meegeven, die aangeroepen worden als een dergelijk event optreedt.

    Verder ben ik net met Nodejs begonnen, dus bedankt voor het artikel in iedergeval, de rest van je artikel is goed bevallen.

    Gr.
    Richard

    • g00glen00b

      Hey, je hebt groot gelijk. Het forken heb ik in een latere tutorial besproken http://g00glen00b.be/node-js-cluster-power/ maar misschien moet ik deze tutorials eens updaten waardoor het niet lijkt alsof het een gebrek is aan Node.js.

      Over het Java verhaal, vreemd, ik meen me te herinneren dat ik tijdens het uitvoeren van de test gekeken heb naar m’n system monitor waar ik kon zien dat alle cores op 100% draaiden. Misschien heb ik dat dan verkeerd gezien.

      In ieder geval, ik zou mijn oude(re) tutorials inderdaad eens moeten bijwerken omdat ze niet altijd 100% correct zijn (meestal schrijf ik de tutorials als ik zelf nog aan het bijleren ben).

  • Bedankt voor deze zeer duidelijke introductie. Vond het met mijn eerder beperkte programming skills heel moeilijk op weg te geraken met deze technologie. Up and running ondertussen.

  • Misschien moeten wij nog even wachten, over 2-3 jaar is er misschien een betere documentatie beschikbaar. Trouwens je WordPress/PHP websites draait erg goed 🙂