For yet another web app, that requires a Facebook OAuth login, I deviated from FB’s code examples and bumped into a race condition!
$#@! happens
- My code:
<script> window.fbAsyncInit=function(){ FB.init({appId:'verylongnumber',cookie:true,version:'v2.0',...}); }; </script> <script src="//connect.facebook.net/en_US/sdk.js"></script>
Reportedly, sdk.js calls fbAsyncInit “after everything is setup[…] and calls made within this function will guarantee the existence of the FB object”, which I’m using later:
$(function(){ window.check_login_status=function(){ FB.getLoginStatus(function(r){
- But, race condition! — browser sometimes triggered jQuery’s ready() before the SDK script executed/finished. I’d occasionally get a warning (should be an error!) in the console: “FB.getLoginStatus() called before calling FB.init() — sdk.js:53”. It’s possible to even encounter “FB is undefined” errors.
- FB’s example code “avoided dealing” with this by dynamically injecting the SDK script, presumably causing a CSSOM block, so sdk.js won’t run before… what? But even this doesn’t work reliably!
// Load the SDK asynchronously (function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/en_US/sdk.js"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));
- So, hey, if it works, why am I rocking the boat? Because Ilya Grigorik writes (comprehensively!) in Script-injected “async scripts” considered harmful: “inline scripts block on CSSOM”, causing performance degradation. We sure don’t want to mess with CSS related performance.
“Hack-around”
- I chained loading sdk.js to guarantee it never calling fbAsyncInit before jQuery’s ready fires. Disgusting.
Solution?
- My code wants to manipulate the DOM, page transitions and stuff, and depends on both DOM ready and the FB.getLoginStatus AJAX response. How to register one callback for two unordered events?
…