Proper way to include Facebook SDK for Javascript and jQuery …

Author: damir October 29, 2016

… and avoid race condition! :)

Although fb is pretty clear on how to do it (http://bit.ly/2eGfFDv) – many developers are still doing it wrong. So this blog post is here to be reminder for me and others, also it will propose small upgrade to the fb recommended practice.

The naive and wrong way to do it

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script>
window.fbAsyncInit = function()
	{
		FB.init({
			appId      : 'your-app-id',
			xfbml      : true,
			version    : 'v2.8'
			});
		
		// do something with DOM and jQuery
		$('#loginbutton,#feedbutton').removeAttr('disabled');
		FB.getLoginStatus(updateStatusCallback);
	};

  (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'));
</script>

The problem with this is the race condition: at the time fbAsyncInit gets called there is no guaranty that DOM is ready and that #loginbutton or #feedbutton is there, ready to be used.

This bug is hard to spot and debug – since it will not always manifest. It is very likely that you as developer with fast connection and computer will never experience this bug – but your clients (visitors) might.

meme

So it is best not to leave this to chance since fix is so easy.

Facebook recommendation

Learn more: http://bit.ly/2eGfFDv

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script>
$(document).ready(function()
{
	$.ajaxSetup({ cache: true });
	
	$.getScript('//connect.facebook.net/en_US/sdk.js',
				function()
				{
					FB.init({
					appId: '{your-app-id}',
					version: 'v2.8'
				}
			);

		$('#loginbutton,#feedbutton').removeAttr('disabled');
		FB.getLoginStatus(updateStatusCallback);
	});
});
</script>

Problem with this approach is that you are changing global jQuery ajax cache settings.

The better way

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<script>
$(document).ready(function()
{
	$.ajax(
			{
				url: '//connect.facebook.net/en_US/sdk.js',
				dataType: 'script',
				cache: true,
				success:function(script, textStatus, jqXHR)
				{
					FB.init(
						{
							appId      : '{your-app-id}',
							xfbml      : true,
							version    : 'v2.8'
						}
					);
					
					$('#loginbutton,#feedbutton').removeAttr('disabled');
					FB.getLoginStatus(updateStatusCallback);
				}
			});
});
</script>

Now we did it. No race condition between jQuery, fb SDK for JS and loading of DOM. Also global jQuery Ajax settings are untouched.

Cheers! :)

Author
damir