簡體   English   中英

如何檢測facebook的FB.init何時完成

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

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

2012年1月4日更新

看起來你不能像以前一樣在FB.init()之后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那么你必須自己寫一些東西,因為沒有官方替代品(大錯誤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");
});

實際上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.Event.subscribe 調用FB.init 之前訂閱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之后立即運行任何代碼,因為不會有異步調用。

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

因此,在頁面就緒事件中,您可以檢查ns.FBInitialized並使用setTimeOut將事件推遲到以后的階段。

雖然上面的一些解決方案有效,但我想我會發布最終的解決方案 - 它定義了一個'就緒'方法,一旦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
    };

})();

我不會使用任何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();
});

這是一個更簡單的方法,既不需要事件也不需要超時。 但它確實需要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初始化函數中,將其釋放:

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

我通過使用全局函數避免使用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
    );
});

您可以訂閱活動:

即)

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

小但重要的通知:

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

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,在我看來這似乎有助於登錄UI並更可靠地驅動功能。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM