Cara mendeteksi kapan FB.init facebook selesai

115

JS SDK lama memiliki fungsi yang disebut FB.ensureInit. SDK baru tampaknya tidak memiliki fungsi seperti itu ... bagaimana saya bisa memastikan bahwa saya tidak melakukan panggilan api sampai dimulai sepenuhnya?

Saya menyertakan ini di bagian atas setiap halaman:

<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
sumber
Lihat tautan ini untuk solusi saya untuk masalah ini. facebook.stackoverflow.com/questions/12399428/…
Remi Grumeau

Jawaban:

138

Pembaruan pada 4 Januari 2012

Sepertinya Anda tidak bisa begitu saja memanggil metode yang bergantung pada FB (misalnya FB.getAuthResponse()) tepat setelah FB.init()seperti sebelumnya, karena FB.init()tampaknya tidak sinkron sekarang. Membungkus kode Anda menjadi FB.getLoginStatus()respons tampaknya melakukan trik untuk mendeteksi ketika API sepenuhnya siap:

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

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

};  

atau jika menggunakan fbEnsureInit()implementasi dari bawah:

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

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

};  

Posting Asli:

Jika Anda ingin menjalankan beberapa skrip saat FB diinisialisasi, Anda dapat meletakkan beberapa fungsi panggilan balik di dalamnya 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
  };

Jika Anda ingin penggantian yang tepat dari FB.ensureInit maka Anda harus menulis sesuatu sendiri karena tidak ada pengganti resmi (kesalahan besar imo). Inilah yang saya gunakan:

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

Pemakaian:

fbEnsureInit(function() {
    console.log("this will be run once FB is initialized");
});
serg
sumber
2
Terima kasih Serg .. kamu adalah legenda!
Pablo
3
Saya tidak dapat menjalankan permintaan API Facebook segera setelah FB.init dipanggil - mungkin karena metode yang saya gunakan adalah 'fql.query'? Bagaimanapun, saya harus menyetel waktu tunggu yang lama pada flag fbApiInit.
Ian Hunter
Terima kasih atas pembaruannya - Saya mengalami masalah yang sama dan solusi terbaru Anda bekerja dengan sempurna!
Terri Ann
@beanland, panggilan api fql.query mengharuskan pengguna telah masuk. Apakah Anda yakin bahwa Anda menjalankan kueri setelah mendapatkan responsekembali FB.getLoginStatus(function(response){}? - perhatikan perbedaan "jawaban yang diperbarui" vs. "jawaban asli" di atas.
tjmehta
@serg terima kasih atas contohnya. Saya harus menunda fungsi saya di fbAsyncInitdalamnya agar dapat dipanggil setelah pemuatanwindow.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

Sebenarnya Facebook sudah menyediakan mekanisme untuk berlangganan event otentikasi.

Dalam kasus Anda, Anda menggunakan " status: true " yang berarti bahwa objek FB akan meminta status login pengguna dari 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
});

Dengan memanggil "FB.getLoginStatus ()" Anda menjalankan permintaan yang sama lagi .

Sebaliknya Anda bisa menggunakan FB.Event.subscribe untuk berlangganan auth.statusChange atau auth.authResponseChange acara SEBELUM Anda menelepon 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
});

Kemungkinan besar, saat menggunakan " status: false " Anda dapat menjalankan kode apa pun tepat setelah FB.init, karena tidak akan ada panggilan asinkron.

shpoont
sumber
CATATAN: Dengan metode ini, satu-satunya peringatan adalah, jika Anda tidak masuk, acara tidak akan dipicu. Buat saja status UI default Anda seolah-olah tidak diautentikasi, dan itu berfungsi dengan sempurna. Anda kemudian dapat memeriksa terhubung atau tidak di dalam event handler.
David C
Selain itu, untuk aplikasi front-end, untuk mempertahankan status login pengguna di antara penyegaran, setel cookieke truedalam objek param init.
MK Safi
12

Berikut adalah solusi jika Anda menggunakan dan 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
sumber
3
Aku menyukainya! Satu-satunya masalah adalah Facebook bersikeras bahwa Anda harus memasukkan kode init FB Anda langsung setelah tag pembuka <body>, dan praktik terbaik mengatakan Anda harus memuat jQuery sebelum tag penutup <body>. Doh! Ayam dan telur. Saya tergoda untuk mengatakan "persetan dengan Anda, Facebook" dan muat FB setelah jQuery.
Ethan Brown
@EthanBrown Saya setuju - halaman Anda mungkin membutuhkan jQuery lebih dari yang dibutuhkan FB sehingga masuk akal. Saya berhenti mencoba memuat jQuery di akhir halaman bertahun-tahun yang lalu ;-)
Simon_Weaver
tambahkan version: 'v2.5'init json lain bijaksana itu tidak akan berhasil .. setidaknya tidak untuk saya. terima kasih atas bantuannya
Vikas Bansal
10

Cara lain untuk memeriksa apakah FB telah diinisialisasi adalah dengan menggunakan kode berikut:

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

Jadi dalam acara siap halaman Anda, Anda dapat memeriksa ns.FBInitialized dan menunda acara ke fase selanjutnya dengan menggunakan setTimeOut.

pengguna2253630
sumber
Ini nyata! Terima kasih!
Thiago Macedo
Ini sederhana. Suka itu
Faris Rayhan
5

Sementara beberapa solusi di atas berfungsi, saya pikir saya akan memposting solusi akhirnya - yang mendefinisikan metode 'siap' yang akan diaktifkan segera setelah FB diinisialisasi dan siap digunakan. Ini memiliki keunggulan dibandingkan solusi lain yang aman untuk dihubungi baik sebelum atau setelah FB siap.

Ini dapat digunakan seperti ini:

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

Berikut file sumbernya (perhatikan bahwa itu didefinisikan dalam namespace '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
sumber
4

Saya telah menghindari penggunaan setTimeout dengan menggunakan fungsi global:

EDIT CATATAN: Saya telah memperbarui skrip pembantu berikut dan membuat kelas yang lebih mudah / sederhana untuk digunakan; lihat di sini ::: https://github.com/tjmehta/fbExec.js

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

fbEnsureInit akan memanggilnya callback setelah FB.init

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

fbEnsureInitAndLoginStatus akan memanggil callbacknya setelah FB.init dan setelah 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 contoh penggunaan:

(FB.login harus dijalankan setelah FB diinisialisasi)

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

fbEnsureInitAndLogin contoh penggunaan:

(FB.api harus dijalankan setelah FB.init dan pengguna FB harus masuk.)

fbEnsureInitAndLoginStatus(function(){
    FB.api(
       //..enter code here
    );
});
tjmehta.dll
sumber
1
Saya menulis kelas pembantu ini yang melakukan hal yang sama seperti di atas dengan cara yang lebih mudah dan lebih bersih; lihat di sini :: github.com/tjmehta/fbExec.js
tjmehta
4

Alih-alih menggunakan setTimeout atau setInterval, saya akan tetap menggunakan objek yang ditangguhkan (implementasi oleh jQuery di sini ). Masih sulit untuk menyelesaikan antrian pada saat yang tepat, karena init tidak memiliki panggilan balik tetapi menggabungkan hasil dengan langganan acara (seperti yang ditunjukkan seseorang sebelum saya), harus melakukan trik dan cukup dekat.

Pseudo-snippet akan terlihat sebagai berikut:

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
sumber
4

Berikut adalah metode yang lebih sederhana, yang tidak memerlukan kejadian atau waktu tunggu. Namun, itu membutuhkan jQuery.

Gunakan jQuery.holdReady() (dokumen)

Jadi, segera setelah skrip jQuery Anda, tunda acara siap.

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

Kemudian, di fungsi init Facebook Anda, lepaskan:

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

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

Kemudian Anda dapat menggunakan acara siap seperti biasa:

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

Anda dapat berlangganan acara:

yaitu)

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

Pemberitahuan kecil tapi PENTING:

  1. FB.getLoginStatusharus dipanggil setelahnya FB.init, jika tidak maka acara tidak akan disulut.

  2. Anda dapat menggunakan FB.Event.subscribe('auth.statusChange', callback), tetapi tidak akan menyala saat pengguna tidak masuk facebook.

Berikut adalah contoh kerja dengan kedua fungsi tersebut

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
sumber
1

API Facebook mengawasi FB._apiKey sehingga Anda dapat melihatnya sebelum memanggil aplikasi API Anda sendiri dengan sesuatu seperti:

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

Tidak yakin ini membuat perbedaan tetapi dalam kasus saya - karena saya ingin memastikan UI sudah siap - saya telah membungkus inisialisasi dengan dokumen jQuery siap (bit terakhir di atas):

  $(document).ready(FBreadyState);

Perhatikan juga bahwa saya TIDAK menggunakan async = true untuk memuat all.js Facebook, yang dalam kasus saya tampaknya membantu masuk ke UI dan menjalankan fitur dengan lebih andal.

jimmont
sumber
1

Terkadang fbAsyncInit tidak berfungsi. Saya tidak tahu mengapa dan menggunakan solusi ini kemudian:

 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
sumber