javascript - 多个异步调用(javascript facebook api)失败

标签 javascript jquery facebook-graph-api jquery-mobile

我在我的 jquery 移动网站 中使用 Facebooks Javascript API ,以便从 Facebook 公共(public)页面下载相册和照片并将其呈现到我的网站。

API 的工作方式非常简单,我让一切都变得相当容易。

到目前为止我所做的事情正在发挥作用

当用户点击按钮时,我加载一个页面,其中调用 javascript FB API 并动态生成特定 Facebook 页面的所有相册的列表,以及所有照片等。这非常有效。当调用 API 时,它仅获取 25 个专辑,而当我有更多专辑要获取时,我有一个“更多专辑”按钮,用户点击该按钮即可再次调用 API 并获取更多专辑。这也很好用...

问题

当我决定要拥有 2 个不同的 Facebook 页面并从中导入相册/照片时,我的问题出现了。所以我制作了一个带有 2 个选项的水平按钮(facebook 页面 1,facebook 页面 2),使导航栏保持不变,当我点击其中一个按钮时,我需要进行 API 调用并获取每个页面的相册。遗憾的是,这不起作用...当我调用两个页面之一时,一切正常。甚至“更多专辑”按钮也有效。但是当我导航到另一个 Facebook 页面时,对 api 的调用不起作用...我不明白为什么...“更多相册”按钮起作用,这意味着我可以多次调用 api。但是为什么当我使用 ajax 导航到 jquery 移动网站上的另一个页面时,调用无法完成?我在 javascript 文件中放置了一个警报,并且看到了它,这意味着该代码被调用。但是当我将警报放入对 api 的实际调用中时,我看不到任何警报......我想这意味着由于某种原因调用被阻止......

知道这里可能发生什么吗?

我的 2 张专辑之一的 javascript 如下所示:

$('#photosNJ').on("pageshow", function() {
        var albumPhotos = new Array();
        var albumThumbnails = new Array();
        var x=0;
        var next;
        var times=0;
        var dataLength=0;

        // start the entire process
        window.fbAsyncInit = function() {
            // init the FB JS SDK 
            FB.init({
                appId      : '564984346887426',                                                  // App ID from the app dashboard
                channelUrl : 'channel.html',                                                     // Channel file for x-domain comms
                status     : true,                                                               // Check Facebook Login status
                xfbml      : true                                                                // Look for social plugins on the page
            });
            $.mobile.loading("show");
            FB.api('169070991963/albums', checkForErrorFirst(getAlbums));
            //$.mobile.loading("hide"); 

        }


        // checkForErrorFirst wraps your function around the error checking code first
        // if there is no response, then your code will not be called
        // this allows you to just write the juicy working code 
        // and not worry about error checking
        function checkForErrorFirst(myFunc) {
            return function(response) { 
                if (!response || response.error) {
                    alert("Error !");
                } else {
                    myFunc(response);
                }
            };  
        }

        function getAlbums(response) {
            //if statement checks , if there are any more albums to load. If not we disable the "More Albums" button.
            if(response.paging.next == undefined) $("#loadMoreAlbums").parent().hide();
            //variable next holds the URL for the next 25(or less) albums
            next = response.paging.cursors.after;
            dataLength = response.data.length + dataLength;
            for (var i=0; i < response.data.length; ++i) {
                processAlbum(response.data[i], i+x);
            }
            x = x+i;
            console.log(x);
        }


        function processAlbum(album, i) {
            FB.api(album.id + "/photos?limit=300", checkForErrorFirst(populateAlbum(album, i)));
        }


        function populateAlbum(album, i) {
            return function(response) {
                for (var k=0; k < response.data.length; ++k){ 
                    albumThumbnails[i] =  albumThumbnails[i]||[];
                    albumThumbnails[i][k] = response.data[k].picture;
                    albumPhotos[i] = albumPhotos[i]||[];
                    albumPhotos[i][k] = response.data[k].source;
                }
                // now that we've populated the album thumbnails and photos, we can render the album
                FB.api(album.cover_photo, checkForErrorFirst(renderAlbum(album, i)));
            };
        }

        function renderAlbum(album, i) {
            times++;
            if(times == dataLength) $.mobile.loading("hide");
            return function(response) {
                var albumName = album.name;
                var albumCover = album.cover_photo;
                var albumId = album.id;
                var numberOfPhotos = album.count;

               // render photos
               $(".albums").append('<li>'+
               '<a href="#Gallery' + i + '"' + 'data-transition="slidedown">'+
               '<img src= "' + response.picture + '"  />'+
               '<h2>' + albumName + '</h2>'+
               '<p>' + "Number of Photos:  " + numberOfPhotos +'</p>'+
               '</a>'+
               '</li>').listview('refresh');

               $("#photosNJ").after('<div data-role="page" data-add-back-btn="true" id=Gallery'+ i +
               ' class="gallery-page"' + ' data-url="Gallery' + i + '"> ' +
               ' <div data-role="header"><h1>Gallery</h1></div> ' + ' <div data-role="content"> ' +
               ' <ul class="gallery"></ul> ' + ' </div> ' +
               ' </div> ');

               for(var n=0; n < albumPhotos[i].length; n++) {
                    $('#Gallery' + i + ' .gallery').append('<li><a href="' + albumPhotos[i][n] 
                    + '"  rel="external"><img src="' +  albumThumbnails[i][n] + '"' + '/> </a> </li>');
               }

               //adding a "More Photos" button inside every album
               // $('#Gallery' + i + ' .gallery').after('<button type="button" class="loadMorePhotos">More Photos...</button>');
             };



        }

        // 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/all.js";
            fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));

        //"More Albums" button
        $("#loadMoreAlbums").click(function(){
            // start the entire process
            window.fbAsyncInit = function() {
            // init the FB JS SDK 
            FB.init({
                appId      : '564984346887426',                                  // App ID from the app dashboard
                channelUrl : 'channel.html',                                     // Channel file for x-domain comms
                status     : true,                                               // Check Facebook Login status
                xfbml      : true                                                // Look for social plugins on the page
            });
            }
            //when the "More Albums" button is pressed , we make a call at the API for the next 25(or less) albums , using the "next" URL
            $.mobile.loading("show");
            FB.api('169070991963/albums?after=' + next +"'", checkForErrorFirst(getAlbums));
        });
});

您可以看到对 api 的调用、动态创建 html 页面以在 ListView 中显示相册、包含照片的相册数量、更多相册按钮等...我的其他 facebook 页面的 javascript是相同的,只有页面 ID 发生变化。此时,我想指出,如果我先加载另一个页面,然后再次加载这个页面,则第二个调用不起作用。这意味着我对其中一张专辑没有特定的问题,而不是第二个调用永远不会运行的问题。

这是 html 页面,以防您需要查看我到底想做什么:

<!DOCTYPE html> 
<html>
<head>
    <meta charset="utf-8">
    <title>jQuery Mobile Web App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!--<link href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" rel="stylesheet" type="text/css"/>-->
    <link rel="stylesheet" href="themes/EspacioJoven.min.css" />
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile.structure-1.3.1.min.css" /> 
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
    <link rel="stylesheet" href="themes/custom.css" />

    <!--Used by PhotoSwipe Plugin -->
    <script type="text/javascript" src="photoSwipe/klass.min.js"></script>
    <script type="text/javascript" src="photoSwipe/code.photoswipe.jquery-3.0.5.min.js"></script>
    <script type='text/javascript' src='photoSwipe/photoSwipeCall.js'></script>      
    <link href="photoSwipe/jquery-mobile.css" type="text/css" rel="stylesheet" />
    <link href="photoSwipe/photoswipe.css" type="text/css" rel="stylesheet" />
    <!--Used by PhotoSwipe Plugin --> 

    <script type='text/javascript' src='javascript/createFb2.js'></script>
    <script type='text/javascript' src='javascript/createFb.js'></script>

</head> 
<body>  
<div data-role="page" id="home" data-theme = "a" >
    <div data-role="content">   
        <h2 id="banner">Joven Mobile</h2>
        <div class="main_menu">
            <ul data-inset="true" data-role="listview">
                <li><a href="#espaJoven"><img src="themes/icons/news.png" alt="Information" class="ui-li-icon">Es Joven</a></li>
                <li><a href="#noJoven"><img src="themes/icons/research.png" alt="Information" class="ui-li-icon">La Noche es Joven</a></li>
                <li><a href="#photosNJ"><img src="themes/icons/staff.png" alt="Information" class="ui-li-icon">Multimedia</a></li>
                <li><a href="#sanrJoven"><img src="themes/icons/students.png" alt="Information" class="ui-li-icon">Sar Joven</a></li>
            </ul>       
        </div> <!-- /main_menu -->
    </div> <!-- /content -->
</div> <!-- /page -->

<div data-role="page" id="photosNJ" data-theme="a" data-add-back-btn="true" data-back-btn-text="Back">
    <!--<script type='text/javascript' src='javascript/createFbAlbums.js'></script> -->
    <div data-role="header" data-id="fixedNav" data-position="fixed">
        <h1>Application Title</h1>
        <a href="#" data-icon="back" data-rel="back" title="Go back">Back</a>
        <div data-role="navbar">
            <ul>
                <li><a href="#photosNJ" class="ui-btn-active ui-state-persist">Photos Noche Joven</a></li>
                <li><a href="#photosEJ">Photos Esp Joen</a></li>
                <li><a href="#videos">Videos</a></li>
            </ul>
        </div> <!-- /navbar -->
    </div> <!-- /header -->
    <div data-role="content">   
        <ul data-role="listview" data-inset="true" class="albums">  
            <!-- Here the albums are created through javascript (createAlbums.js) -->
        </ul>   

        <button type="button" id="loadMoreAlbums">More Albums...</button>   

    </div> <!-- /content -->
    <!-- <div id="fb-root"></div> -->

</div>


<div data-role="page" id="photosEJ" data-theme="a" data-add-back-btn="true" data-back-btn-text="Back">
    <!--<script type='text/javascript' src='javascript/createFbAlbums2.js'></script>-->
    <div data-role="header" data-id="fixedNav" data-position="fixed">
        <h1>Application Title</h1>
        <a href="#" data-icon="back" data-rel="back" title="Go back">Back</a>
        <div data-role="navbar">
            <ul>
                <li><a href="#photosNJ">Photos Noche Joven</a></li>
                <li><a href="#photosEJ" class="ui-btn-active ui-state-persist">Photos Espacio Joven</a></li>
                <li><a href="#videos">Videos</a></li>
            </ul>
        </div> <!-- /navbar -->
    </div> <!-- /header -->
    <div data-role="content">   
        <ul data-role="listview" data-inset="true" class="albums2"> 
            <!-- Here the albums are created through javascript (createAlbums.js) -->
        </ul>       

        <button type="button" id="loadMoreAlbums2">More Albums...</button>      
    </div> <!-- /content -->
    <!-- <div id="fb-root"></div> -->
</div>

</body>
</html>

如果您决定读到这里,非常非常感谢。任何,绝对任何对此的评论或想法对我来说都非常有值(value),所以如果您有任何想法,请与我分享:)

fiddler : http://jsfiddle.net/lessisv/GW4PK/

转到多媒体,那里有 2 个选项卡“Photos Noche Joven”“Photos Espacio Joven”。可以看到第一个加载正常。此外,如果您向下,您可以看到“更多相册”按钮,该按钮也可以正常工作并调用 API。问题是,当我转到“Photos Espacio Joven”时,由于我描述的原因,调用无法正常工作。

最佳答案

首先,您的 loadMoreAlbums 处理程序中不需要 window.fbAsyncInit。您之前定义了相同的函数 - 这就足够了。

其次,您不会多次使用 FB.init - 仅一次。因为它是在 window.fbAsyncInit 中定义的,并且该函数在加载 SDK 时由 Facebook SDK 调用。并且检查脚本是否已经加载:

if (d.getElementById(id)) {return;}

这意味着您加载 FB 脚本一次并初始化 FB 一次。

最主要的是,您不能在一个作用域(“pageshow event”处理程序之一)中初始化 FB 对象 (FB.init),然后在另一个作用域(另一个处理程序)中使用 FB.api。这就是为什么你得到空结果的原因。

您可以尝试多种解决方案。

1.每次页面变化时都可以初始化FB。

只需检查 FB 对象是否存在并调用 window.fbAsyncInit()。您可以通过更改来快速尝试此解决方案

if (d.getElementById(id)) {return;}

if (d.getElementById(id)) {window.fbAsyncInit(); return;} 

这是一种丑陋的方式。

2.你真的应该重构你的代码。

在顶层初始化 FB - 不在两个处理程序中;创建一个处理程序 - 并在页面更改时调用它。您可以传递必要的参数或使用 DOM 元素数据。

PS。每次页面更改时都会添加一个新的 loadMoreAlbums 处理程序。您切换到另一个相册,返回并接到两个电话和双倍数据,再次切换并获得三倍数据。

$(document).on("pageshow", '#photosNJ', function () {
   ...

    $("#loadMoreAlbums").click(function () {
        ...
    });
   ...
});

关于javascript - 多个异步调用(javascript facebook api)失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18270482/

相关文章:

javascript - 使用 jQuery 选择多个类

facebook-graph-api - 在 Facebook 上传多张照片

Jquery 在 Ruby 中启用/禁用选中/取消选中复选框的下拉列表

Facebook FB.login 不会询问用户电子邮件权限?

facebook-graph-api - 自 vs updated_time vs created_time

php - 从通过 JSON 从 PHP/Cakephp 传递到 Javascript/Jquery 的嵌套数组中获取数据

javascript - 在网络上使用 GZIP 压缩十六进制字符串(Javascript)

javascript - Twitter Bootstrap 警报(通知)动态更改文本

javascript - Brightcove Attachevent 失败

javascript - jQuery Opera 焦点事件不起作用