วิธีตรวจสอบเมื่อ 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/…
Remi Grumeau

คำตอบ:


138

อัปเดตเมื่อ 04 ม.ค. 2555

ดูเหมือนว่าคุณจะไม่สามารถเรียกใช้เมธอดที่ขึ้นกับ 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
ขอบคุณ Serg .. คุณคือตำนาน!
Pablo

3
ฉันไม่สามารถเรียกใช้คำขอ API ของ Facebook ได้ทันทีหลังจากเรียก FB.init - อาจเป็นเพราะวิธีที่ฉันใช้คือ 'fql.query'? ไม่ว่าจะด้วยวิธีใดฉันต้องตั้งค่าการหมดเวลาที่ยาวนานบนแฟล็ก fbApiInit
Ian Hunter

ขอบคุณสำหรับการอัปเดต - ฉันประสบปัญหาเดียวกันและโซลูชันที่อัปเดตของคุณทำงานได้อย่างสมบูรณ์แบบ!
Terri Ann

@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 เนื่องจากจะไม่มีการโทรแบบอะซิงโครนัส


หมายเหตุ: ด้วยวิธีนี้ข้อแม้เพียงประการเดียวคือหากคุณไม่ได้เข้าสู่ระบบเหตุการณ์จะไม่ถูกทริกเกอร์ เพียงแค่ทำให้สถานะ UI เริ่มต้นของคุณเหมือนกับว่าไม่ได้รับการรับรองความถูกต้องก็จะทำงานได้อย่างสมบูรณ์ จากนั้นคุณสามารถตรวจสอบการเชื่อมต่อหรือไม่ได้รับอนุญาตภายในตัวจัดการเหตุการณ์
David C

นอกจากนี้สำหรับแอปส่วนหน้าเพื่อรักษาสถานะการเข้าสู่ระบบของผู้ใช้ระหว่างการรีเฟรชให้ตั้งค่าcookieเป็นtrueในวัตถุพารามิเตอร์เริ่มต้น
MK Safi

12

นี่คือวิธีแก้ปัญหาในกรณีที่คุณใช้ และ 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
};

3
ฉันรักมัน! ปัญหาเดียวคือ Facebook ยืนยันว่าคุณควรใส่รหัสเริ่มต้น FB ของคุณโดยตรงหลังแท็กเปิด <body> และแนวทางปฏิบัติที่ดีที่สุดบอกว่าคุณควรโหลด jQuery ก่อนแท็กปิด <body> Doh! ไก่และไข่ ฉันอยากจะพูดว่า "กรูคุณ Facebook" และโหลด FB หลังจาก jQuery
Ethan Brown

@EthanBrown ฉันเห็นด้วย - เพจของคุณอาจต้องการ jQuery มากกว่าที่ต้องการ FB เพื่อให้สมเหตุสมผล ฉันล้มเลิกการพยายามโหลด jQuery ในตอนท้ายของหน้าเมื่อหลายปีก่อน ;-)
Simon_Weaver

เพิ่มversion: 'v2.5'ใน init json อื่น ๆ ฉลาดมันจะไม่ทำงาน .. ที่ leat ไม่ได้สำหรับฉัน ขอบคุณสำหรับความช่วยเหลือ
Vikas Bansal

10

อีกวิธีในการตรวจสอบว่า FB ได้เริ่มต้นหรือไม่โดยใช้รหัสต่อไปนี้:

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

ดังนั้นในเหตุการณ์พร้อมหน้าของคุณคุณสามารถตรวจสอบ nsFBInitialized และเลื่อนเหตุการณ์ไปยังเฟสต่อไปโดยใช้ setTimeOut


นี่แหละของจริง! ขอบคุณ!
Thiago Macedo

นี่เป็นเรื่องง่าย ชอบมัน
Faris Rayhan

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 ไม่มีการเรียกกลับ แต่รวมผลลัพธ์กับการสมัครรับข้อมูลเหตุการณ์ (ตามที่มีคนชี้หน้าฉัน) ควรทำเคล็ดลับและอยู่ใกล้พอ

Pseudo-snippet จะมีลักษณะดังนี้:

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>

จากนั้นในฟังก์ชันเริ่มต้น 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

ประกาศเล็ก ๆ แต่สำคัญ:

  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

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

ไม่แน่ใจว่าสิ่งนี้สร้างความแตกต่าง แต่ในกรณีของฉัน - เพราะฉันต้องการให้แน่ใจว่า UI พร้อม - ฉันได้ห่อการเริ่มต้นด้วยเอกสารของ jQuery พร้อมแล้ว (บิตสุดท้ายด้านบน):

  $(document).ready(FBreadyState);

โปรดทราบด้วยว่าฉันไม่ได้ใช้ async = true เพื่อโหลด all.js ของ Facebook ซึ่งในกรณีของฉันดูเหมือนว่าจะช่วยในการลงชื่อเข้าใช้ UI และคุณสมบัติการขับขี่ได้อย่างน่าเชื่อถือมากขึ้น


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);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.