Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy loading Pattern with Typescript

So with C# and other languages where you have a get and set assessor on properties, it's quite simple to build a lazy loading pattern.

I only recently started playing with Type Script and I'm trying to achieve something the same. I'm loading a Poco with most of it's properties via a Ajax Call. The problem can be described below:

export interface IDeferredObject<T> {
    HasLoaded: boolean;
    DeferredURI: string;         
}

export class Library{        

    LibraryName: string;
    Books: IDeferredObject<Book[]>;        
}   

export class Book {
    Title: string;
    UniqueNumber: number;
}



window.onload = () => {
    //Instantiate new Library
    var lib = new Library();

    //Set some properties
    lib.LibraryName = "Some Library";

    //Set the Deferred URI Rest EndPoint
    lib.Books.DeferredURI = "http://somerestendpoint";
    lib.Books.HasLoaded;      



    //Something will trigger a  GET to lib.Books which then needs to load using the Deferred Uri       

};

Couple of questions: I

  • Is a Interface even the right thing to use here?
  • I'd like to trigger a Load action when something accesses the Library Books Property. Is this even possible?

I know it's quite an open question, just looking for some guidance on how to build that pattern.

Thanks

like image 496
Fox Avatar asked Dec 13 '14 07:12

Fox


2 Answers

Books could be declared as a property(see get and set in TypeScript) and in its getter you can start an ajax call. The only issue is that you cannot know when the ajax call will return and you don't want to block the code execution while value for Books is loading. You can use promise to solve your problem. The following code is using JQuery Deferred Object which is returned by $.ajax call (since 1.5 version).

One change - HasLoaded and DeferredURI. They should reside in "loader class" i.e. Library because in my example Library class is responsible for data retrieval.

export class Library {
    private _loadedBooks: Book[];
    public get Books(): any {
        var result: any = null;
        // Check first if we've already loaded values from remote source and immediately resolve deferred object with a cached value as a result
        if(this.HasLoaded) {
            result = $.Deferred();
            result.resolve(this._loadedBooks);
        }
        else {
            // Initiate ajax call and when it is finished cache the value in a private field
            result = $.ajax(this.DeferredURI)
                          .done((values) => {
                              this.HasLoaded = true;
                              this._loadedBooks = values; 
                          });
        }
        return result;
   }
}

Then code consumer would use Books as following:

var library = new Library();
library.Books.done((books: Book[]) => {
    // do whatever you need with books collection
});

For me this design is counter intuitive and user of this code would not expect the Books field/property to return a deferred object. So I would suggest to change it to method, something like loadBooksAsync(). This name would indicate that the code inside this method is asynchronous and hinting that return value is a deferred object which value would be available somewhere later.

like image 190
Alexander Manekovskiy Avatar answered Oct 02 '22 19:10

Alexander Manekovskiy


Is an Interface even the right thing to use here?

Yes, using interfaces simplifies the coupling problems also in TypeScript

See also: Programmers: Why are interfaces useful?

I'd like to trigger a Load action when something accesses the Library Books Property. Is this even possible?

Yes, it is possible to implement any loading pattern you like. TypeScript is just JavaScript when it comes to code loading.

But, for small to medium sized applications the loading is usually not addressed at TypeScript level but is rather handled by the module loader and script bundler.

Supporting statement:

https://github.com/SlexAxton/yepnope.js#deprecation-notice

Deprecation Notice

...The authors of yepnope feel that the front-end community now offers better software for loading scripts, as well as conditionally loading scripts. None of the APIs for these new tools are quite as easy as yepnope, but we assure you that it's probably worth your while. We don't officially endorse any replacement, however we strongly suggest you follow an approach using modules, and then package up your application using require.js, webpack, browserify, or one of the many other excellent dependency managed build tools...

See also:

  • Stack Overflow: How do AMD loaders work under the hood?
  • Stack Overflow: When to use Requirejs and when to use bundled javascript?
  • Programmers: Practices for organizing JavaScript AMD imports
like image 45
xmojmr Avatar answered Oct 02 '22 19:10

xmojmr