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


115

旧的JS SDK有一个名为FB.ensureInit的函数。新的SDK似乎没有这种功能...如何确保在完全启动之前不进行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>

请参阅此链接以获取我对这个问题的解决方案。 facebook.stackoverflow.com/questions/12399428/...
雷米Grumeau

Answers:


138

2012年1月4日更新

似乎您不能像以前一样立即调用与FB相关的方法(例如FB.getAuthResponse()FB.init(),因为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,则必须自己写点东西,因为没有官方替换(imo很大的错误)。这是我用的:

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

2
谢谢你Serg ..你是一个传奇!
巴勃罗

3
调用FB.init之后,我无法立即运行Facebook API请求-可能是因为我使用的方法是'fql.query'吗?无论哪种方式,我都必须在fbApiInit标志上设置一个较长的超时。
伊恩·亨特

感谢您的更新-我遇到了同样的问题,您的更新解决方案效果很好!
Terri Ann

@ beanland,fql.query api调用要求用户已登录。确定response从返回后,您是否正在运行查询FB.getLoginStatus(function(response){}?-请注意上面“更新后的答案”与“原始答案”的区别。
tjmehta 2012年

@serg谢谢您的示例。我不得不在函数内部加一个延迟,fbAsyncInit以便在加载后调用它window.fbAsyncInit = function() { FB.init({ appId : '*************', channelUrl : 'http://www.mydomain.com', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session oauth : true, // enable OAuth 2.0 xfbml : true // parse XFBML }); setTimeout(function() { myfunction(function (callback) {}, '', '', '' ); }, 1200); };
tq 2012年

38

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

在您的情况下,您使用的是“ status:true ”,这意味着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
});

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

相反,您可以调用FB.init 之前使用FB.Event.subscribe预订auth.statusChangeauth.authResponseChange事件。

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之后立即运行任何代码,因为不会进行异步调用。


注意:使用此方法的唯一警告是,如果您未登录,则不会触发该事件。只需将默认的UI状态设置为未经身份验证即可,并且可以完美运行。然后,您可以在事件处理程序中检查是否已连接或未授权。
David C

另外,对于前端应用程序,要在刷新之间保持用户登录状态,cookietrue在init param对象中设置为。
MK Safi'3

12

这是一种解决方案,以防您使用 和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
};

3
我喜欢它!唯一的问题是,Facebook坚持要求您应在打开<body>标签之后直接添加FB初始化代码,而最佳实践则是您应该在关闭<body>标签之前加载jQuery。h!鸡肉和鸡蛋。我很想说“ screw you,Facebook”并在jQuery之后加载FB。
伊桑·布朗

@EthanBrown我同意-您的页面可能比FB更需要jQuery,因此很有意义。几年前,我放弃了在页面末尾加载jQuery的尝试;-)
Simon_Weaver 2015年

version: 'v2.5'以其他方式添加init json它将不起作用..在leat上对我来说不是。感谢您的帮助
Vikas Bansal 2016年

10

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

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

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


这才是真实的!谢谢!
Thiago Macedo 2015年

这很简单。喜欢它
Faris Rayhan

5

当上述解决方案中的某些起作用时,我认为我会发布最终的解决方案-该解决方案定义了一种“就绪”方法,该方法将在FB初始化并准备就绪后立即执行。与其他解决方案相比,它的优势在于可以在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
    };

})();

4

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

编辑说明:我更新了以下帮助程序脚本,并创建了一个更易于使用的类;在这里查看::: 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需要在初始化FB之后运行)

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

fbEnsureInitAndLogin示例用法:

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

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

1
我编写了这个帮助程序类,它以更简单,更干净的方式执行与上面相同的操作。在这里查看:: github.com/tjmehta/fbExec.js
tjmehta 2012年

4

而不是使用任何setTimeout或setInterval,我将坚持使用延迟的对象(在此处通过jQuery实现)。在适当的时候解析队列仍然很棘手,因为init没有回调,但是将结果与事件订阅结合在一起(正如在我之前指出的那样),应该可以解决问题并且足够接近。

伪代码片段如下所示:

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

4

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

使用jQuery.holdReady() (文档)

因此,在您的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 );


2

小但重要的提示:

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

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

1

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

还要注意,我不是使用async = true来加载Facebook的all.js,就我而言,这似乎有助于登录UI和更可靠地驱动功能。


1

有时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);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.