Working With Asynchronously Loaded JavaScript Objects
Telling browsers to load large JavaScripts asynchronously can significantly improve performance. This prevents the browser from blocking the rendering of the page, allowing it to be viewed more quickly. However, if you are loading dependent files asynchronously, such as a third-party service’s API, making the scripts work together is not automatic.
At Causes we use Facebook’s large (nearly 60 KiB gzipped) JavaScript API on our pages. Although
they recommend loading it asynchronously, we were already
putting our JavaScript at the bottom of the page and weren’t convinced that
async would give us much additional benefit. However, after some non-scientific
performance tests it appeared that switching to asynchronously loading the
Facebook API could reduce the time to DOMContentLoaded
by nearly a full
second on our pages.
After the Facebook API has been loaded asynchronously, it executes
window.fbAsyncInit
, which is where they suggest placing
code that depends on the FB
.
The trouble is, we wanted our JavaScript that interacts with the Facebook API to continue to work even though it is dispersed throughout our scripts, and it may execute before the API was available.
The answers on StackOverflow may work, but they feel inelegant. For
instance, one answer addresses this problem by setting a flag to true
in the fbAsyncInit
callback, and creates a fbEnsureInit
method that uses a
recursive timeout to poll the flag.
We decided to take a different approach. Thankfully, the Facebook API sets up a
single object, FB
, for developers to interact with.
So we developed a class, MethodProxy
, to act as a proxy between the rest of
our code and the FB
object. It accepts an object to forward calls onto, and
it masquerades as an Array by implementing a push
method. The push
method
accepts a single argument of a array whose first position is always a string of
the method name on the FB
object to be executed, followed by as many
arguments to be given to that method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
This allows us to initialize a native Array when the page loads to collect
calls to Facebook’s API. Then, in the fbAsyncInit
callback, we Indiana Jones
style swap out the native array with an instantiation of our MethodProxy
object, which then consumes the queued events by executing them on the FB
object. The end result is a consistent API for our code to use regardless of
the state of Facebook’s asynchronously loaded API.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
MethodProxy
is general enough to be used for other similar cases so we’ve
released it as method-proxy-js, an open source project under
the MIT license and packaged it up for npm
. Installing is as easy as npm
install method-proxy-js
.