如何检测Facebook的FB.init何时完成

旧的JS SDK有一个叫做FB.ensureInit的函数。 新的SDK似乎没有这样的function…我怎么才能确保我不会使API调用,直到它完全启动?

我把它包含在每一页的顶部:

<div id="fb-root"></div> <script> window.fbAsyncInit = function() { FB.init({ appId : '<?php echo $conf['fb']['appid']; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); FB.Canvas.setAutoResize(); }; (function() { var e = document.createElement('script'); e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js'; e.async = true; document.getElementById('fb-root').appendChild(e); }()); </script> 

2012年1月4日更新

看起来像FB.init()类的FB.init()之后, FB.init()似乎不能立即调用FB相关的方法(例如FB.getAuthResponse() ),因为FB.init()似乎是asynchronous的。 将代码包装到FB.getLoginStatus()响应中,似乎可以检测API何时完全准备就绪:

 window.fbAsyncInit = function() { FB.init({ //... }); FB.getLoginStatus(function(response){ runFbInitCriticalCode(); }); }; 

或者如果从下面使用fbEnsureInit()实现:

 window.fbAsyncInit = function() { FB.init({ //... }); FB.getLoginStatus(function(response){ fbApiInit = true; }); }; 

原帖:

如果你想在FB初始化的时候运行一些脚本,你可以在fbAsyncInit一些callback函数:

  window.fbAsyncInit = function() { FB.init({ appId : '<?php echo $conf['fb']['appid']; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); FB.Canvas.setAutoResize(); runFbInitCriticalCode(); //function that contains FB init critical code }; 

如果你想精确的replaceFB.ensureInit,那么你将不得不自己写一些东西,因为没有正式的replace(大错误)。 这是我使用的:

  window.fbAsyncInit = function() { FB.init({ appId : '<?php echo $conf['fb']['appid']; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); FB.Canvas.setAutoResize(); fbApiInit = true; //init flag }; function fbEnsureInit(callback) { if(!window.fbApiInit) { setTimeout(function() {fbEnsureInit(callback);}, 50); } else { if(callback) { callback(); } } } 

用法:

 fbEnsureInit(function() { console.log("this will be run once FB is initialized"); }); 

实际上Facebook已经提供了订阅authentication事件的机制。

在你的情况下,你正在使用“ 状态:真 ”,这意味着FB对象将要求Facebook的用户的login状态。

 FB.init({ appId : '<?php echo $conf['fb']['appid']; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); 

通过调用“FB.getLoginStatus()”您再次运行相同的请求。

相反,您可以使用FB.Event.subscribe订阅auth.statusChangeauth.authResponseChange事件, 然后再调用FB.init

 FB.Event.subscribe('auth.statusChange', function(response) { if(response.status == 'connected') { runFbInitCriticalCode(); } }); FB.init({ appId : '<?php echo $conf['fb']['appid']; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); 

最有可能的是,当使用“ status:false ”时,你可以在FB.init之后运行任何代码,因为不会有asynchronous调用。

这里是一个解决scheme,以防你使用jQuery和Facebookasynchronous延迟加载:

 // listen to an Event $(document).bind('fbInit',function(){ console.log('fbInit complete; FB Object is Available'); }); // FB Async window.fbAsyncInit = function() { FB.init({appId: 'app_id', status: true, cookie: true, oauth:true, xfbml: true}); $(document).trigger('fbInit'); // trigger event }; 

检查FB是否已初始化的另一种方法是使用以下代码:

 ns.FBInitialized = function () { return typeof (FB) != 'undefined' && window.fbAsyncInit.hasRun; }; 

因此,在您的页面就绪事件中,您可以检查ns.FBInitialized,并使用setTimeOut将事件推迟到以后的阶段。

虽然上面的一些解决scheme的工作,我想我会发布我们最终的解决scheme – 它定义了一个“准备好”的方法,只要FB初始化并准备就绪,将触发。 它比其他解决scheme具有优势,在FB准备就绪之前或之后调用是安全的。

它可以像这样使用:

 f52.fb.ready(function() { // safe to use FB here }); 

这里是源文件(注意它是在'f52.fb'命名空间中定义的)。

 if (typeof(f52) === 'undefined') { f52 = {}; } f52.fb = (function () { var fbAppId = f52.inputs.base.fbAppId, fbApiInit = false; var awaitingReady = []; var notifyQ = function() { var i = 0, l = awaitingReady.length; for(i = 0; i < l; i++) { awaitingReady[i](); } }; var ready = function(cb) { if (fbApiInit) { cb(); } else { awaitingReady.push(cb); } }; window.fbAsyncInit = function() { FB.init({ appId: fbAppId, xfbml: true, version: 'v2.0' }); FB.getLoginStatus(function(response){ fbApiInit = true; notifyQ(); }); }; return { /** * Fires callback when FB is initialized and ready for api calls. */ 'ready': ready }; })(); 

我已经通过使用全局函数避免使用setTimeout:

编辑注:我已经更新了以下帮助脚本,并创build了一个更容易/更简单的类; 看看这里::: https://github.com/tjmehta/fbExec.js

 window.fbAsyncInit = function() { FB.init({ //... }); window.fbApiInit = true; //init flag if(window.thisFunctionIsCalledAfterFbInit) window.thisFunctionIsCalledAfterFbInit(); }; 

fbEnsureInit会在FB.init之后调用它的callback函数

 function fbEnsureInit(callback){ if(!window.fbApiInit) { window.thisFunctionIsCalledAfterFbInit = callback; //find this in index.html } else{ callback(); } } 

fbEnsureInitAndLoginStatus将在FB.init和FB.getLoginStatus之后调用它的callback函数

 function fbEnsureInitAndLoginStatus(callback){ runAfterFbInit(function(){ FB.getLoginStatus(function(response){ if (response.status === 'connected') { // the user is logged in and has authenticated your // app, and response.authResponse supplies // the user's ID, a valid access token, a signed // request, and the time the access token // and signed request each expire callback(); } else if (response.status === 'not_authorized') { // the user is logged in to Facebook, // but has not authenticated your app } else { // the user isn't logged in to Facebook. } }); }); } 

fbEnsureInit示例用法:

(在FB初始化后需要运行FB.login)

 fbEnsureInit(function(){ FB.login( //..enter code here ); }); 

fbEnsureInitAndLogin示例用法:

(在FB.init和FB用户必须login后需要运行FB.api。)

 fbEnsureInitAndLoginStatus(function(){ FB.api( //..enter code here ); }); 

而不是使用任何setTimeout或setInterval我会坚持推迟的对象(由jQuery 在这里实现)。 在适当的时候解决队列还是很棘手的,因为init没有callback,但是把结果和事件订阅结合起来(正如有人指出的那样),应该做到这一点,并且足够接近。

伪代码将如下所示:

 FB.Event.subscribe('auth.statusChange', function(response) { if (response.authResponse) { // user has auth'd your app and is logged into Facebook } else { // user has not auth'd your app, or is not logged into Facebook } DeferredObject.resolve(); }); 

这是一个更简单的方法,既不需要事件,也不需要超时。 但是,它确实需要jQuery。

使用jQuery.holdReady() (docs)

所以,紧跟在你的jQuery脚本之后,延迟ready事件。

 <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script> $.holdReady( true ); // don't fire ready until told (ie when FB loaded) </script> 

然后,在你的Facebook init函数中,释放它:

 window.fbAsyncInit = function() { FB.init({ appId: '11111111111111', cookie: true, xfbml: false, version: 'v2.4' }); // release the ready event to execute $.holdReady( false ); }; 

然后,您可以正常使用ready事件:

 $(document).ready( myApp.init ); 

Facebook API监视FB._apiKey,因此您可以在调用您自己的API应用程序之前观察此情况,如下所示:

 window.fbAsyncInit = function() { FB.init({ //...your init object }); function myUseOfFB(){ //...your FB API calls }; function FBreadyState(){ if(FB._apiKey) return myUseOfFB(); setTimeout(FBreadyState, 100); // adjust time as-desired }; FBreadyState(); }; 

不知道这是否有所作为,但在我的情况 – 因为我想确保用户界面已经准备好了 – 我用jQuery的文档准备好了(最后一位在上面):

  $(document).ready(FBreadyState); 

还要注意,我没有使用async = true加载Facebook的all.js,在我的情况下似乎是帮助login到用户界面和更可靠地驱动function。

您可以订阅该事件:

即)

 FB.Event.subscribe('auth.login', function(response) { FB.api('/me', function(response) { alert(response.name); }); }); 

有时fbAsyncInit不起作用。 我不知道为什么,然后使用此解决方法:

  var interval = window.setInterval(function(){ if(typeof FB != 'undefined'){ FB.init({ appId : 'your ID', cookie : true, // enable cookies to allow the server to access// the session xfbml : true, // parse social plugins on this page version : 'v2.3' // use version 2.3 }); FB.getLoginStatus(function(response) { statusChangeCallback(response); }); clearInterval(interval); } },100); 

小但重要通知:

  1. 必须在FB.init之后调用FB.init ,否则不会触发事件。

  2. 你可以使用FB.Event.subscribe('auth.statusChange', callback) ,但是当用户没有在facebook上login时不会触发。

这是两个函数的工作示例

 window.fbAsyncInit = function() { FB.Event.subscribe('auth.statusChange', function(response) { console.log( "FB.Event.subscribe auth.statusChange" ); console.log( response ); }); FB.init({ appId : "YOUR APP KEY HERE", cookie : true, // enable cookies to allow the server to access // the session xfbml : true, // parse social plugins on this page version : 'v2.1', // use version 2.1 status : true }); FB.getLoginStatus(function(response){ console.log( "FB.getLoginStatus" ); console.log( response ); }); }; // 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'));