Reputation: 1631
In the context of the GWT Code Splitting Dev Guide and the suggested module pattern therein to define exclusing code fragments, I understand that the first time the static Module.createAsync(final ModuleClient client)
is called then the code inside the Module
class is downloaded and subsequent calls to this static function will not download the same code fragment again.
The pattern further suggests to cache an INSTANCE
of the Module
class for "for any code that definitely loads after the module".
So my questions are:
After the first call from an initial fragment, does every call to Module.createAsync(final ModuleClient client)
calls the server to check whether code fragment needs to be downloaded or not? Or does the call to onSuccess()
occurs without any server call overhead?
Does the following code in an initial fragment causes the Module
code to be part of the initial download (i.e., not an exclusing fragment)?
>
if (INSTANCE == null)
Module.createAsync(new ModuleClient()
{
@Override
public void onUnavailable(Throwable reason)
{
// Action in case of failure
}
@Override
public void onSuccess(Module instance)
{
instance.showBigComplicatedStuff();
}
});
else
INSTANCE.showBigComplicatedStuff();
In other words:
Does the existence of INSTANCE.showBigComplicatedStuff();
in an initial fragment clause causes the Module
code including showBigComplicatedStuff()
to be part of the initial fragment or is Module
going to be anyway in an exclusive fragment because new Module()
is called within Module.createAsync
(that is within GWT.runAsync
)?
Does this pattern of calling Module.createAsync
the first time only when INSTANCE == null
will help reduce unnecessary asynchronous calls to the server? (Again, I understand that those eventual server calls would not download the corresponding Module
fragment again).
Upvotes: 1
Views: 201
Reputation: 18331
The code you have is incomplete - it isn't obvious why you have INSTANCE
and instance
, and if INSTANCE is a public field generated as part of Module.createAsync, can anything else populate it? I'll try to answer both questions on their own, pointing out any assumptions I'm making along the way
Assuming that objects of type INSTANCE can never possibly be created outside of a GWT.runAsync
, the instance method showBigComplicatedStuff
cannot do anything unless that split point has been loaded (and so at least one instance has been created) - the compiler is smart enough to figure this out. However,
The null check is pointless, for exactly the reason you mention - if you understand that there is no server call to go and get the new GWT.runAsync
fragment, then what async server call do you think is happening inside the GWT.runAsync
? If the code is downloaded and doesn't need to be downloaded again, then there is nothing to download.
There is no overhead of running a GWT.runAsync
the second time since the page has loaded. If caching was implemented correctly, even hitting it the first time after the page is loaded again should be cheap/free (meaning that the server won't be hit again, but there is still the expense of parsing the JS into memory).
So since GWT.runAsync
has no server call overhead after it has been loaded (and so INSTANCE
is non-null
), you shouldn't need to worry about it. GWT will notice that it already has the code it needs and won't attempt to download it again.
Even without so-called 'perfect' caching, this behavior will all hold true. If you happen to be setting caching headers so that your <hashname>.cache.*
files are cached for a year, then the second time that a module or a split point is loaded, it will continue to use the same local results with no network traffic. If there is no perfect cache but the files are still the same on disk, reloading the app will result in a 304 Not Modified
- not free, but not as expensive as downloading again.
A GWT app (using one of the standard linkers) starts off with a appname.nocache.js
file - this file contains the <hashname>
strings mentioned above which only change when code changes, so this must not be cached so that code changes can occur, the client sees the change right away. The initial fragment for a given set of properties (i.e. 'which browser' * 'which locale' * 'which form factor' etc) then is downloaded or read from the cache as <hashname>.cache.js
, and then when a given splitpoint <N>
is hit, the split point is fetched as deferredjs/<hashname>/<N>.cache.js
.
With all that said, the theory behind the Module.createAsync
thing is to be an async factory, so you certainly can use it the way you are describing. In this case though if only having one instance is important, I might have a getOrCreateAsync
that does the singleton bits inside the module class - as long as the class is responsible for creating the instance and providing it, it might as well always provide it. It really depends on how you are using the instance, what it contains, etc.
Upvotes: 3