Cách phát hiện khi FB.init của facebook hoàn tất


115

JS SDK cũ có một chức năng được gọi là FB.ensureInit. SDK mới dường như không có chức năng như vậy ... làm cách nào để đảm bảo rằng tôi không thực hiện lệnh gọi api cho đến khi nó được khởi tạo hoàn toàn?

Tôi bao gồm điều này ở đầu mỗi trang:

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

Xem liên kết này để biết giải pháp của tôi cho vấn đề này. facebook.stackoverflow.com/questions/12399428/…
Remi Grumeau

Câu trả lời:


138

Cập nhật vào ngày 04/01/2012

Có vẻ như bạn không thể chỉ gọi các phương thức phụ thuộc FB (ví dụ FB.getAuthResponse()) ngay sau đó FB.init()như trước đây, vì FB.init()có vẻ như bây giờ là không đồng bộ. Gói mã của bạn vào FB.getLoginStatus()phản hồi dường như thực hiện mẹo phát hiện khi nào API đã hoàn toàn sẵn sàng:

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

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

};  

hoặc nếu sử dụng fbEnsureInit()triển khai từ bên dưới:

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

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

};  

Bài gốc:

Nếu bạn chỉ muốn chạy một số tập lệnh khi FB được khởi tạo, bạn có thể đặt một số hàm gọi lại bên trong 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
  };

Nếu bạn muốn thay thế chính xác FB.ensureInit thì bạn sẽ phải tự viết một cái gì đó vì không có sự thay thế chính thức (sai lầm lớn imo). Đây là những gì tôi sử dụng:

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

Sử dụng:

fbEnsureInit(function() {
    console.log("this will be run once FB is initialized");
});

2
Cảm ơn bạn Serg .. bạn là một huyền thoại!
Pablo

3
Tôi không thể chạy yêu cầu API Facebook ngay lập tức sau khi FB.init được gọi - có lẽ vì phương thức tôi đang sử dụng là 'fql.query'? Dù bằng cách nào, tôi phải đặt một khoảng thời gian chờ dài trên cờ fbApiInit.
Ian Hunter

Cảm ơn bạn đã cập nhật - Tôi cũng gặp sự cố tương tự và giải pháp cập nhật của bạn hoạt động hoàn hảo!
Terri Ann

Các lệnh gọi api @beanland, fql.query yêu cầu người dùng đã đăng nhập. Bạn có chắc chắn rằng mình đang chạy truy vấn sau khi nhận được responsephản hồi từ FB.getLoginStatus(function(response){}không? - lưu ý sự khác biệt giữa "câu trả lời cập nhật" so với "câu trả lời gốc" ở trên.
tjmehta

@serg cảm ơn bạn về ví dụ. Tôi đã phải đặt một sự chậm trễ ở bên trong chức năng của tôi fbAsyncInitcho nó được gọi sau khi tảiwindow.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

Trên thực tế, Facebook đã cung cấp cơ chế đăng ký các sự kiện xác thực.

Trong trường hợp của bạn, bạn đang sử dụng " status: true " có nghĩa là đối tượng FB sẽ yêu cầu Facebook cấp trạng thái đăng nhập của người dùng.

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

Bằng cách gọi "FB.getLoginStatus ()", bạn đang chạy lại yêu cầu tương tự .

Thay vào đó bạn có thể sử dụng FB.Event.subscribe để đăng ký auth.statusChange hoặc auth.authResponseChange kiện TRƯỚC KHI bạn gọi 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
});

Rất có thể, khi sử dụng " status: false ", bạn có thể chạy bất kỳ mã nào ngay sau FB.init, vì sẽ không có lệnh gọi không đồng bộ.


LƯU Ý: Với phương pháp này, lưu ý duy nhất là, nếu bạn chưa đăng nhập, sự kiện sẽ không được kích hoạt. Chỉ cần đặt trạng thái giao diện người dùng mặc định của bạn như thể chưa được xác thực và nó hoạt động hoàn hảo. Sau đó, bạn có thể kiểm tra xem đã kết nối hay không_authorized bên trong trình xử lý sự kiện.
David C

Ngoài ra, đối với các ứng dụng front-end, để duy trì trạng thái đăng nhập của người dùng giữa các lần làm mới, hãy đặt cookiethành truetrong đối tượng init param.
MK Safi

12

Đây là một giải pháp trong trường hợp bạn sử dụng và Facebook Đang tải chậm không đồng bộ:

// 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
Tôi thích nó! Vấn đề duy nhất là Facebook khẳng định rằng bạn nên bao gồm mã FB init của mình ngay sau thẻ mở <body> và phương pháp hay nhất nói rằng bạn nên tải jQuery trước thẻ <body> đóng. Doh! Gà và trứng. Tôi muốn nói "vặn bạn, Facebook" và tải FB sau jQuery.
Ethan Brown

@EthanBrown Tôi đồng ý - trang của bạn có thể cần jQuery hơn là cần FB để điều đó có ý nghĩa. Tôi đã từ bỏ việc cố gắng tải jQuery ở cuối trang cách đây nhiều năm ;-)
Simon_Weaver

thêm version: 'v2.5'vào init json khác khôn ngoan nó sẽ không hoạt động .. tại leat đã không cho tôi. cảm ơn vì sự giúp đỡ
Vikas Bansal

10

Một cách khác để kiểm tra xem FB đã được khởi tạo hay chưa là sử dụng đoạn mã sau:

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

Vì vậy, trong sự kiện sẵn sàng trang của bạn, bạn có thể kiểm tra ns.FBInitialized và hoãn sự kiện sang giai đoạn sau bằng cách sử dụng setTimeOut.


Đây là điều thực sự! Cảm ơn!
Thiago Macedo

Đây là một trong những đơn giản. Thích nó
Faris Rayhan

5

Trong khi một số giải pháp ở trên hoạt động, tôi nghĩ rằng tôi sẽ đăng giải pháp cuối cùng của chúng tôi - xác định phương thức 'sẵn sàng' sẽ kích hoạt ngay khi FB được khởi tạo và sẵn sàng hoạt động. Nó có lợi thế hơn so với các giải pháp khác là nó an toàn để gọi trước hoặc sau khi FB sẵn sàng.

Nó có thể được sử dụng như vậy:

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

Đây là tệp nguồn (lưu ý rằng nó được xác định trong không gian tên '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

Tôi đã tránh sử dụng setTimeout bằng cách sử dụng một hàm toàn cầu:

CHỈNH SỬA LƯU Ý: Tôi đã cập nhật các tập lệnh trợ giúp sau và tạo một lớp dễ sử dụng hơn / đơn giản hơn; kiểm tra nó tại đây ::: https://github.com/tjmehta/fbExec.js

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

fbEnsureInit sẽ gọi nó là cuộc gọi lại sau FB.init

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

fbEnsureInitAndLoginStatus sẽ gọi nó là callback sau FB.init và sau 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.

      }
    });
  });
}

ví dụ sử dụng fbEnsureInit:

(FB.login cần được chạy sau khi FB đã được khởi tạo)

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

Ví dụ sử dụng fbEnsureInitAndLogin:

(FB.api cần được chạy sau khi FB.init và người dùng FB phải đăng nhập.)

fbEnsureInitAndLoginStatus(function(){
    FB.api(
       //..enter code here
    );
});

1
Tôi đã viết lớp trợ giúp này thực hiện tương tự như trên một cách dễ dàng và sạch sẽ hơn; hãy xem nó tại đây :: github.com/tjmehta/fbExec.js
tjmehta

4

Thay vì sử dụng bất kỳ setTimeout hoặc setInterval nào, tôi sẽ gắn bó với các đối tượng bị trì hoãn (triển khai bằng jQuery tại đây ). Vẫn còn khó khăn để giải quyết hàng đợi trong thời điểm thích hợp, vì init không có lệnh gọi lại nhưng kết hợp kết quả với đăng ký sự kiện (như ai đó đã chỉ trước tôi), nên thực hiện thủ thuật và đủ gần.

Đoạn mã giả sẽ trông như sau:

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

Đây là một phương pháp đơn giản hơn, không yêu cầu sự kiện hoặc thời gian chờ. Tuy nhiên, nó yêu cầu jQuery.

Sử dụng jQuery.holdReady() (tài liệu)

Vì vậy, ngay sau tập lệnh jQuery của bạn, hãy trì hoãn sự kiện đã sẵn sàng.

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

Sau đó, trong chức năng init Facebook của bạn, hãy phát hành nó:

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

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

Sau đó, bạn có thể sử dụng sự kiện sẵn sàng như bình thường:

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

2

Bạn có thể đăng ký sự kiện:

I E)

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

2

Thông báo nhỏ nhưng QUAN TRỌNG:

  1. FB.getLoginStatusphải được gọi sau FB.init, nếu không nó sẽ không kích hoạt sự kiện.

  2. bạn có thể sử dụng FB.Event.subscribe('auth.statusChange', callback), nhưng nó sẽ không kích hoạt khi người dùng không đăng nhập facebook.

Đây là ví dụ làm việc với cả hai chức năng

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 Facebook theo dõi FB._apiKey, vì vậy bạn có thể theo dõi điều này trước khi gọi ứng dụng API của riêng bạn với một cái gì đó như:

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

Không chắc điều này tạo ra sự khác biệt nhưng trong trường hợp của tôi - vì tôi muốn chắc chắn rằng giao diện người dùng đã sẵn sàng - tôi đã gói quá trình khởi tạo với tài liệu của jQuery đã sẵn sàng (bit cuối cùng ở trên):

  $(document).ready(FBreadyState);

Cũng xin lưu ý rằng tôi KHÔNG sử dụng async = true để tải all.js của Facebook, điều này trong trường hợp của tôi dường như đang giúp đăng nhập vào giao diện người dùng và lái xe các tính năng đáng tin cậy hơn.


1

Đôi khi fbAsyncInit không hoạt động. Tôi không biết tại sao và sử dụng giải pháp này sau đó:

 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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.