Як визначити, коли FB.init у Facebook завершено


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/…
Ремі Грумеу

Відповіді:


138

Оновлення 04 січня 2012 року

Схоже, ви не можете просто викликати залежні від 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
Дякую, Серг .. ти легенда!
Пабло

3
Я не в змозі запустити запит API Facebook відразу після виклику FB.init - можливо, тому, що метод, який я використовую, - це "fql.query"? У будь-якому випадку, я повинен встановити тривалий час очікування на прапорі fbApiInit.
Ян Хантер

Дякую за оновлення - у мене була та сама проблема, і ваше оновлене рішення працювало чудово!
Террі Енн

@beanland, fql.query api-дзвінки вимагають, щоб користувач увійшов у систему. Ви впевнені, що виконуєте запит після responseповернення FB.getLoginStatus(function(response){}? - відзначте різницю "оновлена ​​відповідь" проти "оригінальна відповідь" вище.
tjmehta

@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

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.Event.subscribe підписатися на auth.statusChange або auth.authResponseChange події ПЕРЕД ви телефонуєте 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
});

Швидше за все, при використанні " status: false " ви можете запустити будь-який код відразу після FB.init, оскільки не буде асинхронних дзвінків.


ПРИМІТКА. За допомогою цього методу єдиний застереження полягає в тому, що якщо ви не ввійшли в систему, подія не буде запущено. Просто зробіть стан інтерфейсу за замовчуванням так, як якщо б він не був автентифікований, і він працює чудово. Потім ви можете перевірити наявність підключеного або не_авторизованого всередині обробника подій.
Давид C

Крім того , для інтерфейсних програм, щоб підтримувати користувальницький статус входу між оновленнями, набором cookieдля trueв об'єкті INIT парів.
МК Сафі

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 наполягає на тому, що ви повинні включити свій код FB init безпосередньо після відкриття тегу <body>, а найкраща практика говорить, що ви повинні завантажити jQuery перед закриттям тега <body>. До! Курка і яйце. Я спокушаюсь сказати "накрутити тебе, Facebook" і завантажувати FB після jQuery.
Етан Браун

@EthanBrown Я згоден - Ваша сторінка, ймовірно, потребує jQuery більше, ніж їй потрібна FB, так що це має сенс. Я кинув спробу завантажити jQuery в кінці сторінки років тому ;-)
Simon_Weaver

додати version: 'v2.5'в init json інші мудрі, це не спрацює .. at liat не для мене. дякую за допомогу
Вікас Бансал

10

Ще один спосіб перевірити, чи ініціалізується FB, це використовувати наступний код:

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

Таким чином, у своїй події, готовій до сторінки, ви можете перевірити ns.FBInitialized та відкласти подію на пізню фазу, використовуючи setTimeOut.


Це справжня річ! Дякую!
Тіаго Македосе

Це просто. Сподобалось
Фаріс Райхан

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

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 затримуйте готову подію.

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

Потім у своїй функції init у Facebook відпустіть:

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

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

Тоді ви можете використовувати готовий захід як звичайний:

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

2

Ви можете підписатися на подію:

тобто)

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

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

API 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 для завантаження all.js Facebook, що в моєму випадку, здається, допомагає увійти в інтерфейс і надійніше керувати функціями.


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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.