Thomas Bandt

Über mich | Kontakt | Archiv

Stolperfalle: Module in Node.js sind statisch

Baut man sich seine eigenen Module, wie das die Philosophie von Node.js vorsieht, muss man aufpassen, dass man bei mehrfacher Verwendung nicht in Konflikte gerät. Denn diese sind faktisch statisch und funktionieren wie Singletons.

Als Beispiel soll dieses simple Demo-Modul dienen:

(function(module) {
    "use strict";

    var _name = "Foo";

    module.getName = function() {
        return _name;
    }

    module.setName = function(name) {
        _name = name;
    }
}(exports));

Der private Member _name ist zunächst “Foo” und kann über die Methode setName(name) beliebig geändert werden.

Ein kleines Beispiel:

(function() {
    "use strict";

    var http = require("http");

    var demo1 = require("./app/demo");
    var demo2 = require("./app/demo");

    var server = http.createServer(function(request, response) {
        response.write("1 - " + demo1.getName() + "\n");
        response.write("2 - " + demo2.getName() + "\n");

        demo1.setName("Bar");

        response.write("1 - " + demo1.getName() + "\n");
        response.write("2 - " + demo2.getName() + "\n");

        response.end();
    });

    server.listen(8080);
}());

Erzeugt werden zwei “Instanzen” des Demo-Moduls: demo1 und demo2. Zunächst wird für jede “Instanz” der Name ausgegeben, was erwartbar zur Ausgabe von “Foo” und “Foo” führt.

Anschließend wird für die erste “Instanz” demo1 der Name auf “Bar gesetzt”, was vermuten lassen könnte, dass die folgende Ausgabe nun aus “Bar” (demo1) und “Foo” (demo2) besteht.

1 - Foo
2 - Foo
1 - Bar
2 - Foo

Tut sie aber nicht: stattdessen ist der Wert nun für beide “Instanzen” auf “Bar” gesetzt.

1 - Foo
2 - Foo
1 - Bar
2 - Bar

Aktualisiert man die Seite im Browser, bestehen gar alle Ausgaben nur noch aus “Bar”.

1 - Bar
2 - Bar
1 - Bar
2 - Bar

Der Grund dafür ist, dass Module nur ein einziges Mal instanziiert werden - egal wie häufig man sie irgendwo per require() einbindet. Damit gibt es also faktisch keine Instanzen und alle Aktionen, die auf demo1 durchgeführt werden, betreffen auch demo2, da demo1 faktisch demo2 entspricht.

Keine revolutionäre, für Einsteiger in Node.js aber eine wichtige Erkenntnis ;-).

Kommentare

  1. Mike Bild schrieb am Freitag, 28. November 2014 12:38:00 Uhr:

    mach mal

    module.exports = function(name){
    var _name = name || 'Foo';
    this.getName = function(){
    return _name;
    };
    }

    schon kannst du

    var Demo = require('./app/demo');

    var demo1 = new Demo();
    demo1.getName();

    var demo2 = new Demo('Bar');
    demo2.getName();
    machen ;)


  2. Mike Bild schrieb am Freitag, 28. November 2014 12:44:00 Uhr:

    ... heißt:

    A) ja die Module selbst werden einmal geladen und dann gecached.
    B) es liegt in der Hand des Entwicklers ein das gewünschte Object-Creation-Pattern zu verwenden.

    Alternativ könnte das auch so aussehen

    module.exports = function(){
    'use strict';

    var _name = 'Foo';
    return {
    getName: function(){
    return _name;
    };
    };

  3. Thomas schrieb am Samstag, 29. November 2014 13:15:00 Uhr:

    Hey, klar geht das so :-). Ich finde nur, dass man als Einsteiger durchaus auch vermuten könnte, dass require("xyz") ein neues "Objekt instanziiert" – dass das nicht so ist, sollte man wissen, wenn man nicht in seltsames Verhalten laufen will.


« Zurück  |  Weiter »