So erkennen Sie, wann Facebooks FB.init vollständig ist

115

Das alte JS SDK hatte eine Funktion namens FB.ensureInit. Das neue SDK scheint keine solche Funktion zu haben ... Wie kann ich sicherstellen, dass ich keine API-Aufrufe tätige, bis es vollständig initiiert ist?

Ich füge dies oben auf jeder Seite ein:

<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>
Pablo
quelle
Unter diesem Link finden Sie meine Lösung für dieses Problem. facebook.stackoverflow.com/questions/12399428/…
Remi Grumeau

Antworten:

138

Update am 04. Januar 2012

Es scheint, dass Sie nicht einfach FB-abhängige Methoden (zum Beispiel FB.getAuthResponse()) direkt nach FB.init()wie zuvor aufrufen können , da FB.init()dies jetzt asynchron zu sein scheint. Das Einschließen Ihres Codes in eine FB.getLoginStatus()Antwort scheint den Trick zu tun, zu erkennen, wann die API vollständig bereit ist:

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

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

};  

oder wenn Sie die fbEnsureInit()Implementierung von unten verwenden:

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

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

};  

Ursprünglicher Beitrag:

Wenn Sie bei der Initialisierung des FB nur ein Skript ausführen möchten, können Sie eine Rückruffunktion einfügen 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
  };

Wenn Sie FB.ensureInit exakt ersetzen möchten, müssen Sie selbst etwas schreiben, da es keinen offiziellen Ersatz gibt (großer Fehler imo). Folgendes benutze ich:

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

Verwendung:

fbEnsureInit(function() {
    console.log("this will be run once FB is initialized");
});
serg
quelle
2
Danke Serg .. du bist eine Legende!
Pablo
3
Ich kann eine Facebook-API-Anfrage nicht unmittelbar nach dem Aufruf von FB.init ausführen - vielleicht, weil die von mir verwendete Methode 'fql.query' ist? In jedem Fall muss ich für das Flag fbApiInit ein längeres Timeout festlegen.
Ian Hunter
Vielen Dank für das Update - ich hatte das gleiche Problem und Ihre aktualisierte Lösung hat perfekt funktioniert!
Terri Ann
@beanland erfordern fql.query api Anrufe , dass der Benutzer angemeldet hat. Sind Sie sicher , dass Sie die Abfrage ausgeführt wird, nachdem ein immer responsewieder aus FB.getLoginStatus(function(response){}? - Beachten Sie den Unterschied zwischen der "aktualisierten Antwort" und der "ursprünglichen Antwort" oben.
tjmehta
@serg danke für das Beispiel. Ich musste meine Funktion verzögern fbAsyncInit, damit sie nach dem Laden aufgerufen werden konntewindow.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
38

Tatsächlich hat Facebook bereits einen Mechanismus zum Abonnieren von Authentifizierungsereignissen bereitgestellt.

In Ihrem Fall verwenden Sie " status: true ", was bedeutet, dass das FB-Objekt Facebook nach dem Anmeldestatus des Benutzers anfordert.

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

Durch Aufrufen von "FB.getLoginStatus ()" führen Sie dieselbe Anforderung erneut aus .

Stattdessen könnten Sie FB.Event.subscribe abonnieren auth.statusChange oder auth.authResponseChange Ereignis bevor Sie FB.init rufen

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

Wenn Sie " status: false " verwenden, können Sie höchstwahrscheinlich jeden Code direkt nach FB.init ausführen, da keine asynchronen Aufrufe stattfinden.

shpoont
quelle
HINWEIS: Bei dieser Methode besteht die einzige Einschränkung darin, dass das Ereignis nicht ausgelöst wird, wenn Sie nicht angemeldet sind. Stellen Sie einfach Ihren Standard-UI-Status so ein, als ob er nicht authentifiziert wäre, und er funktioniert einwandfrei. Sie können dann im Ereignishandler prüfen, ob eine Verbindung besteht oder nicht autorisiert ist.
David C
Für Front-End-Apps, um den Benutzeranmeldestatus zwischen den Aktualisierungen beizubehalten cookie, wird dies trueim init param-Objekt festgelegt.
MK Safi
12

Hier ist eine Lösung für den Fall, dass Sie verwenden und Facebook Asynchronous Lazy Loading:

// 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
};
vladaman
quelle
3
Ich liebe es! Das einzige Problem ist, dass Facebook darauf besteht, dass Sie Ihren FB-Init-Code direkt nach dem öffnenden <body> -Tag einfügen. Nach bewährten Methoden sollten Sie jQuery vor dem schließenden <body> -Tag laden. Doh! Huhn und Ei. Ich bin verlockend zu sagen "Scheiß auf dich, Facebook" und FB nach jQuery zu laden.
Ethan Brown
@EthanBrown Ich stimme zu - Ihre Seite benötigt wahrscheinlich mehr jQuery als FB, also macht das Sinn. Ich habe es vor Jahren aufgegeben, jQuery am Ende der Seite zu laden
;-)
füge version: 'v2.5'im init json hinzu, sonst würde es nicht funktionieren .. zumindest nicht für mich. Danke für die Hilfe
Vikas Bansal
10

Eine andere Möglichkeit, um zu überprüfen, ob der FB initialisiert wurde, ist die Verwendung des folgenden Codes:

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

Auf diese Weise können Sie in Ihrem seitenbereiten Ereignis ns.FBInitialized überprüfen und das Ereignis mithilfe von setTimeOut auf eine spätere Phase verschieben.

user2253630
quelle
Das ist die wahre Sache! Vielen Dank!
Thiago Macedo
Das ist einfach. Gefällt
mir
5

Während einige der oben genannten Lösungen funktionieren, dachte ich, ich würde unsere endgültige Lösung veröffentlichen - die eine "Bereit" -Methode definiert, die ausgelöst wird, sobald FB initialisiert und einsatzbereit ist. Es hat gegenüber anderen Lösungen den Vorteil, dass Sie sicher anrufen können, bevor oder nachdem FB bereit ist.

Es kann wie folgt verwendet werden:

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

Hier ist die Quelldatei (beachten Sie, dass sie in einem 'f52.fb'-Namespace definiert ist).

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

})();
Karl Rosaen
quelle
4

Ich habe die Verwendung von setTimeout durch die Verwendung einer globalen Funktion vermieden:

BEARBEITEN HINWEIS: Ich habe die folgenden Hilfsskripte aktualisiert und eine Klasse erstellt, die einfacher / benutzerfreundlicher ist. Überprüfen Sie es hier ::: https://github.com/tjmehta/fbExec.js

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

fbEnsureInit ruft seinen Rückruf nach FB.init auf

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

fbEnsureInitAndLoginStatus ruft seinen Rückruf nach FB.init und nach FB.getLoginStatus auf

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.

      }
    });
  });
}

Beispiel für die Verwendung von fbEnsureInit:

(FB.login muss ausgeführt werden, nachdem FB initialisiert wurde)

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

Beispiel für die Verwendung von fbEnsureInitAndLogin:

(FB.api muss ausgeführt werden, nachdem FB.init und der FB-Benutzer angemeldet sind.)

fbEnsureInitAndLoginStatus(function(){
    FB.api(
       //..enter code here
    );
});
tjmehta
quelle
1
Ich habe diese Hilfsklasse geschrieben, die auf einfachere und sauberere Weise die gleiche Leistung wie oben erbringt. Überprüfen Sie es hier :: github.com/tjmehta/fbExec.js
tjmehta
4

Anstatt setTimeout oder setInterval zu verwenden, würde ich mich an verzögerte Objekte halten (Implementierung durch jQuery hier ). Es ist immer noch schwierig, die Warteschlange im richtigen Moment aufzulösen, da init keine Rückrufe hat, aber das Kombinieren des Ergebnisses mit dem Ereignisabonnement (wie jemand vor mir gezeigt hat) den Trick machen und nah genug sein sollte.

Pseudo-Snippet würde wie folgt aussehen:

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

Hier ist eine einfachere Methode, die weder Ereignisse noch Zeitüberschreitungen erfordert. Es erfordert jedoch jQuery.

Verwenden Sie jQuery.holdReady() (docs)

Verzögern Sie also sofort nach Ihrem jQuery-Skript das Ready-Ereignis.

<!-- 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>

Lassen Sie es dann in Ihrer Facebook-Init-Funktion los:

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

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

Dann können Sie das Ereignis ready wie gewohnt verwenden:

$(document).ready( myApp.init );
voidstate
quelle
2

Sie können die Veranstaltung abonnieren:

dh)

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

Kleine aber wichtige Hinweise:

  1. FB.getLoginStatusmuss nach aufgerufen werden FB.init, sonst wird das Ereignis nicht ausgelöst.

  2. Sie können verwenden FB.Event.subscribe('auth.statusChange', callback), aber es wird nicht ausgelöst, wenn der Benutzer nicht bei Facebook angemeldet ist.

Hier ist das Arbeitsbeispiel mit beiden Funktionen

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'));
Mher Aghabalyan
quelle
1

Die Facebook-API sucht nach dem FB._apiKey, sodass Sie darauf achten können, bevor Sie Ihre eigene Anwendung der API mit folgenden Elementen aufrufen:

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

Ich bin mir nicht sicher, ob dies einen Unterschied macht, aber in meinem Fall - weil ich sichergehen wollte, dass die Benutzeroberfläche bereit ist - habe ich die Initialisierung mit dem bereitstehenden Dokument von jQuery abgeschlossen (letztes Bit oben):

  $(document).ready(FBreadyState);

Beachten Sie auch, dass ich NICHT async = true verwende, um all.js von Facebook zu laden. In meinem Fall scheint dies dabei zu helfen, sich zuverlässiger bei der Benutzeroberfläche anzumelden und Funktionen zu steuern.

jimmont
quelle
1

Manchmal funktioniert fbAsyncInit nicht. Ich weiß nicht warum und verwende diese Problemumgehung dann:

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