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

旧的 JS SDK 有一个名为 FB.ensureInit 的函数。新的 SDK 似乎没有这样的功能... 我怎样才能确保我不做 api 调用,直到它完全启动?

I include this in the top of every page:

<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>
126010 次浏览

2012年1月4日更新

似乎不能像以前那样在 FB.init()之后立即调用依赖于 FB 的方法(例如 FB.getAuthResponse()) ,因为 FB.init()现在似乎是异步的。将您的代码包装到 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中放一些回调函数:

  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
};

如果你想精确地替换 FB.ensureInit,那么你必须自己写一些东西,因为没有正式的替换(大错特错)。以下是我使用的方法:

  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");
});

我通过使用一个全局函数来避免使用 setTimeout:

编辑注意: 我已经更新了以下 helper 脚本,并创建了一个更容易/更简单使用的类; 请在这里查看: : : https://github.com/tjmehta/fbExec.js

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

FbEnsureInit 将在 FB.init 之后调用它的回调

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

FbEnsureInitAndLoginStatus 将在 FB.init 之后和 FB.getLoginStatus 之后调用它的回调

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.login needs to be run after FB has been initialized)

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

FbEnsureInitAndLogin 用法示例:

(FB.api 需要在 FB.init 和 FB 用户登录后运行。)

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

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();
};

不知道这是否会有所不同,但是在我的例子中——因为我想确保 UI 已经准备好了——我已经用 jQuery 的文档(上面最后一点)包装了初始化:

  $(document).ready(FBreadyState);

还要注意的是,我并没有使用 sync = true 来加载 Facebook 的 all.js,在我的例子中,这似乎有助于登录 UI 并更可靠地驱动特性。

你可以订阅以下活动:

(即)

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

实际上 Facebook 已经提供了一种订阅身份验证事件的机制。

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

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
});

By calling "FB.getLoginStatus()" you are running the same request 再来一次.

相反,您可以使用 FB.Event 订阅订阅 Auth.statusChangeAuthResponseChange事件 之前,您可以调用 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
});

最有可能的情况是,当使用“ 状态: 错误”时,您可以在 FB.init 之后运行任何代码,因为不会有异步调用。

我不使用任何 setTimeout 或 setInterval,而是坚持使用延迟对象(由 jQuery给你实现)。在适当的时候解析队列仍然很棘手,因为 init 没有回调,但是将 result 和事件订阅结合起来(正如有人在我之前指出的) ,应该可以做到这一点,并且足够接近。

Pseudo-snippet would look as follows:

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();
});

如果你使用 和 Facebook 异步延迟加载,这里有一个解决方案:

// 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;
};

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

虽然上面的一些解决方案是有效的,但是我认为我应该发布我们的最终解决方案——它定义了一个“就绪”方法,一旦 FB 初始化并准备就绪,该方法就会触发。它比其他解决方案有优势,在 FB 准备好之前或之后调用都是安全的。

它可以这样使用:

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

Here's the source file (note that it's defined within a 'f52.fb' namespace).

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
};


})();

有时 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);

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

使用 jQuery.holdReady() (文件)

因此,在 jQuery 脚本之后,立即延迟就绪事件。

<!-- 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 );
};

然后,您可以像往常一样使用就绪事件:

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

小而重要的告示:

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

  2. 你可以使用 FB.Event.subscribe('auth.statusChange', callback),但它不会触发当用户没有登录在 Facebook。

下面是两个函数的工作示例

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'));