Как определить, когда завершена функция facebook FB.init
У старого 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>
Ответы
Ответ 1
Обновление от 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;
});
};
Оригинальное сообщение:
Если вы хотите просто запустить некоторый script, когда 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
Фактически Facebook уже предоставил механизм для подписки на события аутентификации.
В вашем случае вы используете " статус: истина", что означает, что объект 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, потому что асинхронных вызовов не будет.
Ответ 3
Вот решение, если вы используете jquery и Facebook Асинхронный Lazy Загрузка:
// 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
};
Ответ 4
Еще один способ проверить, был ли FB инициализирован, используя следующий код:
ns.FBInitialized = function () {
return typeof (FB) != 'undefined' && window.fbAsyncInit.hasRun;
};
Таким образом, в событии готовности страницы вы можете проверить ns.FBInitialized и отложить событие до более поздней фазы с помощью setTimeOut.
Ответ 5
В то время как некоторые из вышеперечисленных решений работают, я думал, что опубликую наше возможное решение, которое определяет метод "ready", который будет срабатывать, как только 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
};
})();
Ответ 6
Я избегал использования setTimeout с помощью глобальной функции:
EDIT ПРИМЕЧАНИЕ. Я обновил следующие вспомогательные скрипты и создал класс, который проще/проще использовать; проверьте здесь: 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 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
);
});
Ответ 7
Вместо использования какого-либо 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();
});
Ответ 8
Здесь более простой метод, который не требует ни событий, ни тайм-аутов. Однако для этого требуется jQuery.
Используйте jQuery.holdReady()
(docs)
Итак, сразу после вашего jQuery script запустите готовое событие.
<!-- 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 init, отпустите его:
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 );
Ответ 9
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, что в моем случае, по-видимому, помогает с более надежным входом в интерфейс и функциями управления.
Ответ 10
Вы можете подписаться на событие:
т)
FB.Event.subscribe('auth.login', function(response) {
FB.api('/me', function(response) {
alert(response.name);
});
});
Ответ 11
Иногда 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);
Ответ 12
Маленькие, но ВАЖНЫЕ примечания:
-
FB.getLoginStatus
должен вызываться после FB.init
, иначе он не будет запускать событие.
-
вы можете использовать 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'));