Javascript 如何检测 facebook 的 FB.init 何时完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3548493/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:07:16  来源:igfitidea点击:

How to detect when facebook's FB.init is complete

javascriptfacebook

提问by Pablo

The old JS SDK had a function called FB.ensureInit. The new SDK does not seem to have such function... how can I ensure that I do not make api calls until it is fully initiated?

旧的 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>

回答by serg

Update on Jan 04, 2012

2012 年 1 月 4 日更新

It seems like you can't just call FB-dependent methods (for example FB.getAuthResponse()) right after FB.init()like before, as FB.init()seems to be asynchronous now. Wrapping your code into FB.getLoginStatus()response seems to do the trick of detecting when API is fully ready:

似乎您不能像以前一样立即调用依赖于 FB 的方法(例如FB.getAuthResponse()FB.init(),因为FB.init()现在似乎是异步的。将您的代码包装成FB.getLoginStatus()响应似乎可以检测 API 何时完全就绪:

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

    FB.getLoginStatus(function(response){
        runFbInitCriticalCode(); 
    });

};  

or if using fbEnsureInit()implementation from below:

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

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

    FB.getLoginStatus(function(response){
        fbApiInit = true;
    });

};  


Original Post:

原帖:

If you want to just run some script when FB is initialized you can put some callback function inside fbAsyncInit:

如果你只想在 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
  };

If you want exact replacement of FB.ensureInit then you would have to write something on your own as there is no official replacement (big mistake imo). Here is what I use:

如果你想完全替换 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();
            }
        }
    }

Usage:

用法:

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

回答by shpoont

Actually Facebook has already provided a mechanism to subscribe to authentication events.

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

In your case you are using "status: true" which means that FB object will request Facebook for user's login status.

在您的情况下,您使用的是“ 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
});

By calling "FB.getLoginStatus()" you are running the same request again.

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

Instead you could use FB.Event.subscribeto subscribe to auth.statusChangeor auth.authResponseChangeevent BEFOREyou call FB.init

相反,您可以调用 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
});

Most likely, when using "status: false" you can run any code right after FB.init, because there will be no asynchronous calls.

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

回答by vladaman

Here is a solution in case you use jqueryand Facebook Asynchronous Lazy Loading:

如果您使用jquery和 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
};

回答by user2253630

Another way to check if FB has initialized is by using the following code:

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

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

Thus in your page ready event you could check ns.FBInitialized and defer the event to later phase by using setTimeOut.

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

回答by Karl Rosaen

While some of the above solutions work, I thought I'd post our eventual solution - which defines a 'ready' method that will fire as soon as FB is initialized and ready to go. It has the advantage over other solutions that it's safe to call either before or after FB is ready.

虽然上述一些解决方案有效,但我想我会发布我们的最终解决方案 - 它定义了一个“就绪”方法,该方法将在 FB 初始化并准备就绪后立即触发。与其他解决方案相比,它的优势在于在 FB 准备好之前或之后调用都是安全的。

It can be used like so:

它可以像这样使用:

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

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

这是源文件(请注意,它是在“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
    };

})();

回答by tjmehta

I've avoided using setTimeout by using a global function:

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

EDIT NOTE: I've updated the following helper scripts and created a class that easier/simpler to use; check it out here ::: https://github.com/tjmehta/fbExec.js

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

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

fbEnsureInit will call it's callback after FB.init

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

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

fbEnsureInitAndLoginStatus will call it's callback after FB.init and after FB.getLoginStatus

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 example usage:

fbEnsureInit 示例用法:

(FB.login needs to be run after FB has been initialized)

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

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

fbEnsureInitAndLogin example usage:

fbEnsureInitAndLogin 示例用法:

(FB.api needs to be run after FB.init and FB user must be logged in.)

(FB.api需要在FB.init之后运行,FB用户必须登录。)

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

回答by Drachenfels

Instead of using any setTimeout or setInterval I would stick to deferred objects (implementation by jQuery here). It's still tricky to resolve queue in proper moment, because init don't have callbacks but combining result with event subscription (as someone pointed before me), should do the trick and be close enough.

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

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

回答by voidstate

Here's a simpler method, that requires neither events or timeouts. It does require jQuery, however.

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

Use jQuery.holdReady()(docs)

使用jQuery.holdReady()(文档)

So, immediately after your jQuery script, delay the ready event.

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

Then, in your Facebook init function, release it:

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

window.fbAsyncInit = function() {
    FB.init({
        appId: '11111111111111',
        cookie: true,
        xfbml: false,
        version: 'v2.4'
    });

    // release the ready event to execute
    $.holdReady( false );
};

Then you can use the ready event as normal:

然后您可以正常使用就绪事件:

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

回答by Mher Aghabalyan

Small but IMPORTANT notices:

小而重要的通知:

  1. FB.getLoginStatusmust be called after FB.init, otherwise it will not fire the event.

  2. you can use FB.Event.subscribe('auth.statusChange', callback), but it will not fire when user is not logged in facebook.

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

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

Here is the working example with both functions

这是具有两个功能的工作示例

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

回答by Jonathan Tonge

You can subscribe to the event:

您可以订阅该事件:

ie)

IE)

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