Search code examples
javascriptclassconstructorsafe-publication

does "unsafe publication" exist in Javascript?


I just wrote the following Javascript code...

class Team {
    constructor(id, eventHandler) {
        this.id = id;
        this._eventHandler = eventHandler;
        this._eventHandler.trigger("NewTeam", this); // my concerning line
    }
}

I have a Java background. In Java it's considered dangerous for an object to share a reference to itself from its constructor ("unsafe publication"). This is because other threads might operate on the object before it's in a valid state.

Is it also risky in Javascript? Is it considered bad practice?

I can only think of one issue: if we want to extend Team then it would be tricky to make additional properties visible to eventHandler.trigger("NewTeam",__).


Solution

  • Since Javascript is single threaded (except for webWorkers which are not in play here), the concern you mention for Java does not apply here to Javascript. No other code will be running at the same time as the constructor. This is one of the great simplifications of Javascript's single threaded and event driven nature.

    If you synchronously trigger an event or make a function call and pass an unfinished object to that event handler or function call, then you are, of course, asking for trouble because you would be passing an unfinished object reference to other code that will run before you finish your constructor.

    As long as the object you are passing is in a valid state when you pass it, this is not a problem, but if you passed an unfinished object, then you are indeed asking for trouble, but this is really just common sense programming, nothing to do with threading or concurrency.


    In your specific case:

    class Team {
        constructor(id, eventHandler) {
            this.id = id;
            this._eventHandler = eventHandler;
            this._eventHandler.trigger("NewTeam", this); // my concerning line
        }
    }
    

    You have created a vulnerability. If Team is subclassed, then you will call this._eventHandler.trigger("NewTeam", this); and be passing it this before the subclass has necessarily finished its constructor. Depending upon the specific implementation, this could be a problem so that practice is not always safe. If the .trigger() could be called on the next tick(using something like setImmediate() or nextTick(), then that would always be safe because the object and any subclasses would always be done being constructed before it was called.