DEV Community

Cover image for Reactive Resources Management
Jin
Jin

Posted on • Updated on • Originally published at mol.hyoo.ru

Reactive Resources Management

The channel that creates, configures and memoizes an object will be called a factory. The consumer does not care when and how the object is created. Just as it doesn’t matter when this object needs to be destroyed. He just needs to know how to get it at the next recalc. And the factory itself will figure out when to create it and when to destroy it.

For example, let's create a project that will own all our tasks and an account that will own all our projects:

class Project extends Entity {

    @mems task( id: number ) {
        return new Task( id )
    }

}

class Account extends Entity {

    @mems project( id: number ) {
        return new Project( id )
    }

}
Enter fullscreen mode Exit fullscreen mode

Now we can receive an object through one channel, and through it access another channel to receive a third object, and be sure that there will be no Null Pointer Exception or memory leaks:

class App extends Object {

    @mems static account( id: number ) {
        return new Account( id )
    }

    @act static main() {
        console.log( this.account(1) )
        console.log( this.account(1).project(23) )
        console.log( this.account(1).project(23).task(456) )
    }

    static [ Symbol.toStringTag ] = 'App'

}

App.main()
// logs
//      App.account(1)
//      App.account(1).project(23)
//      App.account(1).project(23).task(456)
Enter fullscreen mode Exit fullscreen mode

In this example, 3 objects will be automatically created, which will be kept in memory until the function completes, and then will be automatically destroyed.

For all this to work, objects must implement the destructor method, which signals to the factory that this is not just a structure, but an object whose lifetime can be controlled**. When it is created, constructor is called automatically by JS runtime. And the destructor for destruction is called automatically by the factory when it, through the dependency tracking system, understands that the object is no longer needed by anyone.

Since the reactive system always knows which objects are actually needed, and not just available via links from the runtime root, this makes it theoretically possible to abandon the garbage collector altogether, and at the same time have deterministic release of resources. In JS you cannot disable the garbage collector, but in other languages this is an interesting direction for further research.

In addition to automatically controlling the life cycle of objects, these lazy factories give us one more bonus: the ability to raise only part of the application, and not the whole of it. This is especially true during component testing, where we can take the entire application, call the logic we are interested in, and be sure that only the part of the application necessary for it is raised. This gives extremely short test execution time, even without the use of mocks.

class Test {

    @act data_fields_should_be_independent() {

        // given
        cosnt task = App.account(1).project(23).task(456)
        $mol_assert_unique( task.duration(), 3 )
        $mol_assert_unique( task.title(), 'test title' )

        // when
        task.title( 'test title' )
        task.duration( 3 )

        // then
        $mol_assert_equal( task.duration(), 3 )
        $mol_assert_equal( task.title(), 'test title' )

    }

}
Enter fullscreen mode Exit fullscreen mode

In this test, only 3 objects are created, regardless of how many other channels, factories, dependencies and other abstractions there are in our application.

As you can see, a reactive system can simulate an entire world for you on the fly, and you won't even notice it until it breaks, of course.

Top comments (0)