Comment détecter la fin du FB.init de Facebook

115

L'ancien SDK JS avait une fonction appelée FB.ensureInit. Le nouveau SDK ne semble pas avoir une telle fonction ... comment puis-je m'assurer que je ne passe pas d'appels API tant qu'il n'est pas complètement lancé?

J'inclus ceci en haut de chaque 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>
Pablo
la source
Voir ce lien pour ma solution à ce problème. facebook.stackoverflow.com/questions/12399428/…
Remi Grumeau

Réponses:

138

Mise à jour le 04 janvier 2012

Il semble que vous ne pouvez pas simplement appeler des méthodes dépendantes de FB (par exemple FB.getAuthResponse()) juste après FB.init()comme avant, comme cela FB.init()semble être asynchrone maintenant. Envelopper votre code en FB.getLoginStatus()réponse semble faire le tour de détecter quand l'API est complètement prête:

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

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

};  

ou si vous utilisez l' fbEnsureInit()implémentation ci-dessous:

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

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

};  

Message original:

Si vous voulez simplement exécuter un script lorsque FB est initialisé, vous pouvez mettre une fonction de rappel à l'intérieur 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
  };

Si vous voulez un remplacement exact de FB.ensureInit, vous devrez écrire quelque chose par vous-même car il n'y a pas de remplacement officiel (grosse erreur imo). Voici ce que j'utilise:

  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");
});
serg
la source
2
Merci Serg .. vous êtes une légende!
Pablo
3
Je ne suis pas en mesure d'exécuter une demande d'API Facebook immédiatement après l'appel de FB.init - peut-être parce que la méthode que j'utilise est «fql.query»? Dans tous les cas, je dois définir un long délai d'expiration sur l'indicateur fbApiInit.
Ian Hunter
Merci pour la mise à jour - J'avais le même problème et votre solution mise à jour fonctionnait parfaitement!
Terri Ann
@beanland, les appels à l'API fql.query nécessitent que l'utilisateur se soit connecté. Êtes-vous sûr d'exécuter la requête après avoir obtenu un responseretour FB.getLoginStatus(function(response){}? - notez la différence entre la "réponse mise à jour" et la "réponse originale" ci-dessus.
tjmehta
@serg merci pour l'exemple. J'ai dû mettre un retard sur ma fonction à l'intérieur fbAsyncInitpour qu'elle soit appelée après le chargementwindow.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

En fait, Facebook a déjà fourni un mécanisme pour s'abonner aux événements d'authentification.

Dans votre cas, vous utilisez " status: true ", ce qui signifie que l'objet FB demandera à Facebook le statut de connexion de l'utilisateur.

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

En appelant « FB.getLoginStatus () » vous exécutez la même demande à nouveau .

Vous pourriez plutôt utiliser FB.Event.subscribe pour vous abonner à auth.statusChange ou auth.authResponseChange événement AVANT que vous appelez 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
});

Très probablement, lorsque vous utilisez " status: false ", vous pouvez exécuter n'importe quel code juste après FB.init, car il n'y aura pas d'appels asynchrones.

shpoont
la source
REMARQUE: avec cette méthode, la seule mise en garde est que, si vous n'êtes pas connecté, l'événement ne sera pas déclenché. Faites simplement l'état de votre interface utilisateur par défaut comme s'il n'était pas authentifié et cela fonctionne parfaitement. Vous pouvez ensuite vérifier la connexion ou la non-autorisation à l'intérieur du gestionnaire d'événements.
David C
En outre, pour les applications frontales, pour maintenir l'état de connexion de l'utilisateur entre les actualisations, défini cookiesur truedans l'objet init param.
MK Safi
12

Voici une solution au cas où vous utiliseriez et chargement paresseux asynchrone 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
};
Vladaman
la source
3
J'aime cela! Le seul problème est que Facebook insiste pour que vous incluiez votre code d'initialisation FB directement après la balise d'ouverture <body>, et les meilleures pratiques indiquent que vous devez charger jQuery avant la balise de fermeture <body>. Doh! Poulet et œuf. Je suis tenté de dire "va te faire foutre, Facebook" et de charger FB après jQuery.
Ethan Brown
@EthanBrown Je suis d'accord - votre page a probablement besoin de jQuery plus que de FB, donc cela a du sens. J'ai renoncé à essayer de charger jQuery à la fin de la page il y a des années ;-)
Simon_Weaver
ajouter version: 'v2.5'dans le json init autrement il ne fonctionnera pas .. au moins n'a pas pour moi. merci pour l'aide
Vikas Bansal
10

Une autre façon de vérifier si FB s'est initialisé consiste à utiliser le code suivant:

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

Ainsi, dans votre événement de page prête, vous pouvez vérifier ns.FBInitialized et reporter l'événement à une phase ultérieure en utilisant setTimeOut.

user2253630
la source
C'est la vraie chose! Merci!
Thiago Macedo
C'est simple. Like it
Faris Rayhan
5

Bien que certaines des solutions ci-dessus fonctionnent, j'ai pensé publier notre solution éventuelle - qui définit une méthode `` prête '' qui se déclenchera dès que FB est initialisé et prêt à fonctionner. Il présente l'avantage par rapport aux autres solutions d'appeler en toute sécurité avant ou après que FB soit prêt.

Il peut être utilisé comme ceci:

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

Voici le fichier source (notez qu'il est défini dans un espace de noms '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
    };

})();
Karl Rosaen
la source
4

J'ai évité d'utiliser setTimeout en utilisant une fonction globale:

NOTE DE MODIFICATION: J'ai mis à jour les scripts d'assistance suivants et créé une classe plus facile / plus simple à utiliser; vérifiez-le ici ::: https://github.com/tjmehta/fbExec.js

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

fbEnsureInit appellera son rappel après FB.init

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

fbEnsureInitAndLoginStatus appellera son rappel après FB.init et après 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.

      }
    });
  });
}

Exemple d'utilisation de fbEnsureInit:

(FB.login doit être exécuté après l'initialisation du FB)

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

Exemple d'utilisation de fbEnsureInitAndLogin:

(FB.api doit être exécuté après FB.init et l'utilisateur FB doit être connecté.)

fbEnsureInitAndLoginStatus(function(){
    FB.api(
       //..enter code here
    );
});
tjmehta
la source
1
J'ai écrit cette classe d'aide qui exécute la même chose que ci-dessus d'une manière plus simple et plus propre; Découvrez-le ici :: github.com/tjmehta/fbExec.js
tjmehta
4

Au lieu d'utiliser n'importe quel setTimeout ou setInterval, je m'en tiendrais aux objets différés (implémentation par jQuery ici ). Il est toujours difficile de résoudre la file d'attente au bon moment, car init n'a pas de rappel, mais en combinant le résultat avec l'abonnement aux événements (comme quelqu'un l'a indiqué avant moi), cela devrait faire l'affaire et être suffisamment proche.

Le pseudo-extrait ressemblerait à ceci:

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
la source
4

Voici une méthode plus simple, qui ne nécessite ni événements ni délais. Cependant, il nécessite jQuery.

Utiliser jQuery.holdReady() (docs)

Donc, immédiatement après votre script jQuery, retardez l'événement 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>

Ensuite, dans votre fonction d'initialisation Facebook, relâchez-le:

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

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

Ensuite, vous pouvez utiliser l'événement ready comme d'habitude:

$(document).ready( myApp.init );
voidstate
la source
2

Vous pouvez vous abonner à l'événement:

c'est à dire)

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

Avis petits mais IMPORTANTS:

  1. FB.getLoginStatusdoit être appelé après FB.init, sinon il ne déclenchera pas l'événement.

  2. vous pouvez utiliser FB.Event.subscribe('auth.statusChange', callback), mais il ne se déclenchera pas lorsque l'utilisateur n'est pas connecté à Facebook.

Voici l'exemple de travail avec les deux fonctions

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
la source
1

L'API Facebook surveille la FB._apiKey afin que vous puissiez surveiller cela avant d'appeler votre propre application de l'API avec quelque chose comme:

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

Je ne suis pas sûr que cela fasse une différence mais dans mon cas - parce que je voulais être sûr que l'interface utilisateur était prête - j'ai encapsulé l'initialisation avec le document de jQuery prêt (dernier bit ci-dessus):

  $(document).ready(FBreadyState);

Notez également que je n'utilise PAS async = true pour charger all.js de Facebook, ce qui, dans mon cas, semble aider à me connecter à l'interface utilisateur et à gérer les fonctionnalités de manière plus fiable.

Jimmont
la source
1

Parfois, fbAsyncInit ne fonctionne pas. Je ne sais pas pourquoi et utiliser cette solution de contournement alors:

 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
la source