WSC 3.0 — AJAX Requests

  • WCF 2.x provides a nice and convenient way to issue AJAX requests via WCF.Action.Proxy which is a wrapper around jQuery's $.ajax itself. While it does work smoothly and offer a consistent way to accomplish this, it requires a bit too much effort to properly use it within a class. We've already dove into some changes that will take place with WCF 2.2 and it is about time for some real world examples to showcase you the strength of the new API.


    Lets consider a typical class that can be seen in WCF 2.0/2.1:


    This example shows three major downsides of the current API:

    • In line 2 we need to define the property _proxy (we could define it on the fly within init(), but extending the object on runtime is rather expensive!)
    • Lines 5-7 create a new instance of WCF.Action.Proxy which is kind of bad because we're spawning that instance regardless if one of the click events are ever invoked
    • In line 14 and 15 we need to define actionName and most important className which usually do not change within the class


    We all know that developers are lazy (and so are we), thus we built a new API which circumvents all these downsides by utilizing a lazy factory to do the job.


    Lets look at a sample module definition:


    There are three major differences:

    • We've at no point defined an instance of the Ajax class
    • We've never bound any methods in first place
    • The _click-event in line 14-16 does not set anything else except the data we actually want to transmit


    The important point lies in line 14: Ajax.api(this, …. The Ajax class uses the first argument to store an internal request object which is re-used every time for performance reasons, this is pretty much the same as this._proxy = new WCF.Action.Proxy(…);. In addition it uses the _ajaxSetup() method which returns the initialization data including the special key data. But wait, let's go through this step by step!


    We've eliminated the need to statically define an AJAX request object, the first call to Ajax.api() will implicitly spawn a request object at the second you actually need it. All data that needs to be set to construct a request object are taken from the return value of _ajaxSetup, this means your methods do not have to care if the request object was already created, it will always be there if they attempt to call it. In addition there are a few methods that are automatically called if they are present, even though none of them need to be actually implemented:

    • _ajaxFailure() handles failed requests, similar to the failure callback of WCF.Action.Proxy
    • _ajaxFinalize() is invoked once the request has been completed, regardless whether it failed or succeeded, similar to the after callback of WCF.Action.Proxy
    • _ajaxSuccess() handles successful request, similar to the success callback of WCF.Action.Proxy

    The only requirement for an object is to implement _ajaxSetup(), everything else is optional and you can even make _ajaxSetup() return an empty object if you wish to.


    There is one really cool thing I would like to highlight at this point: The data key of the object returned by _ajaxSetup(). The value will be automatically "pinned", which means it will be added to the data that is sent to the server with every request made. You don't need to specify the className over and over, the Ajax class will automatically fill in that bit and save you from writing the same lines over and over again. Yet, these "pinned" values are considered weak, they can be overridden if you explicitly provide them when calling Ajax.api()!


    All these changes should help you to build efficient and fast code without caring to much what happens under the hood, it is the framework's responsibility to take care of it. Oh, and bonus points for having an API that does not require any framework whatsoever, it is pure vanilla JavaScript.



    By the way, you can also directly require AjaxRequest and work with the plain request object, see https://github.com/WoltLab/WCF…F/Ajax/Request.js#L36-L53 for the full list of available options.

    Alexander Ebert
    Senior Developer WoltLab® GmbH

  • Is there a special reason for the rather complex singleton pattern with overwriting the function prototype and new in the second code snippet? A simple object literal would be sufficient and way more performant (though it probably wouldn't matter in the framework's use cases, I suppose).
    Moreover, since you specifically pointed out the reduced bounding calls, you could thereby remove this from that piece of code altogether and remove the bind call for the click handler as well.

  • A simple object literal would be sufficient and way more performant

    Yes, but after all the actual difference is non-existent in a real-world scenario and we consistently use this pattern in every module, regardless if it is a singleton or just export the function (e.g. return FooBar; instead of return new FooBar();). Having a unified pattern is more important than applying micro-optimizations where the difference can only be measured by comparing CPU cycles.


    Moreover, since you specifically pointed out the reduced bounding calls, you could thereby remove this from that piece of code altogether and remove the bind call for the click handler as well.

    Unless you're inlining the _click function directly and using something among the lines of var self = this; to abuse scoping, how do you want to preserve the this context? Also the examples above are just examples, in a real-world code where I expect the handler to be bound to a lot of elements I would store the bound callback in a variable instead to decrease the payload of binding with each iteration.

    Alexander Ebert
    Senior Developer WoltLab® GmbH

  • Having a unified pattern is more important than applying micro-optimizations where the difference can only be measured by comparing CPU cycles.

    I disagree here. Currently only one line, or more precise, the new keyword, highlights whether just a collection of functions (singleton) is returned or that the developer has to create an instance of an object type. The object literal would make it perfectly clear how other developers have to work with that module at first glance.

    Unless you're inlining the _click function directly and using something among the lines of var self = this; to abuse scoping, how do you want to preserve the this context? Also the examples above are just examples, in a real-world code where I expect the handler to be bound to a lot of elements I would store the bound callback in a variable instead to decrease the payload of binding with each iteration.

    Just to make it clear, I talk about something along the lines of the third code snipped here: http://usejsdoc.org/tags-exports.html
    Inside your addEventListener call, you can reference to the handler by FooBar._click (or still use this since it would point to FooBar anyway). Or, if you like, make the handler function correctly private by not assigning it to the returned object in first place.
    However, in the handler you can replace all current this calls with FooBar and remove the explicit binding in addEventListener.
    We talk about a singleton here, there is no point in using this in first place since there is only exactly one instance anyway, which you can (and probably should) easily store in an ordinary variable.

  • Despite the discussion of how to setup a module...i really appreciate the new Ajax API, not having to determine the same stuff over and over again is great.
    I just took a quick look over the Javascript code. As far as i can see i can still define a success closure within my request (so i don't need to distinguish multiple successes in _ajaxSuccess) right?