【问题标题】:How to make 2 asynchronous API calls execute one after another如何让 2 个异步 API 调用一个接一个地执行
【发布时间】:2013-06-26 14:59:24
【问题描述】:

我正在使用 facebooks javascript API 从 Facebook 页面导入 albumsphotos

首先,我通过 API 调用导入 albums

然后我通过另一个 API 调用将每个 albumphotos 导入到数组中。

最后一步 - 通过另一个 API 调用,我导入了每张专辑的 coverPhotos,这样我就可以用所有的 albums 和它们的 coverPhotos 创建一个 jquery mobile listView

我的代码如下所示:

<script>
    var albumPhotos = new Array();
    var albumThumbnails = new Array();
    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
        });

        // Additional initialization code such as adding Event Listeners goes here
        FB.api('169070991963/albums', function(response) {
            if(!response || response.error) {
                // render error
                alert("Noo!!");
            } else {
                // render photos
                for(var i=0; i<response.data.length; i++) { 
                    (function (i) {
                        var albumName = response.data[i].name;
                        var albumCover = response.data[i].cover_photo;
                        var albumId = response.data[i].id;
                        var numberOfPhotos = response.data[i].count;

                        FB.api(albumId + "/photos", function(response) {
                            if(!response || response.error) {
                                // render error
                                alert("Noo!!");
                            } else {
                                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;
                                }
                            }
                        }); 

                        console.log(albumName);
                        FB.api( albumCover, function(response) {
                            if(!response || response.error) {
                                // render error
                                alert("Noo!!");
                            } else {
                                // 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');

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

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

这段代码有问题:

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

更具体地说:albumPhotos[i].length

因为对 API 的调用是异步的,所以之前实际创建数组 albumPhotos 的 API 调用尚未完成,这意味着该数组尚未定义

在调用最后一个 API 调用FB.api(albumCover, function(response) {..}之前我需要一个方法

确保之前的 API 调用:

FB.api(albumId + "/photos", function(response) {
    if(!response || response.error) {
        // render error
        alert("Noo!!");
    } else {
        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;
        }
    }
});

已经结束了。

在此处执行此类操作的最简单方法是什么?

【问题讨论】:

标签: javascript api asynchronous


【解决方案1】:

简短的回答,您需要使依赖于正在填充的专辑的所有代码在它们被填充后工作。这意味着复制和粘贴一些代码。

长答案...

首先,让我们重构一下。为了你的理智,你会想要这个功能

// 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("Noo!!");
    } else {
      myFunc(response);
    }
  };
}

这样你就可以做这样的事情:

function DoWork(response) {
  // usefulwork...
}

FB 调用看起来像……

FB.api('169070991963/albums', checkForErrorFirst(DoWork));

既然我们已经解决了这个问题,我们需要将您的每个调用链接在一起,因为它们相互依赖。我和你一样在全局空间中设置了albumPhotos 和albumThumbnails。

var albumPhotos = new Array();
var albumThumbnails = new Array();

function getAlbums(response) {
  for (var i=0; i < response.data.length; ++i) {
    processAlbum(response.data[i], i);
  } 
}

function processAlbum(album, i) {
  FB.api(album.id + "/photos", 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) {
  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');

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


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

// start the entire process
FB.api('169070991963/albums', checkForErrorFirst(getAlbums));

显然,我没有对此进行测试 - 但我认为这会帮助您保持理智。

【讨论】:

  • 真是一个令人难以置信的答案。通过几行更改,这就像一个魅力。好吧,我真的非常感谢你,安迪。 :D 不需要库,不需要任何太复杂的东西。简单优雅的解决方案。真是太棒了。
  • 我越是反复阅读您的代码,就越欣赏它的复杂性。出于好奇,您以前是否曾使用过此功能,或者您只是将其从头顶上写下来?与此相比,我正在做的事情太丑了(但是我对 js 完全陌生)。
  • 你好@Andy!既然你是唯一可以帮助我的人,我还有一个问题要问你。您能否检查一下:stackoverflow.com/questions/17474006/… 我现在正在寻找的是如何知道 API 调用何时完成以及 html 页面已被动态创建。我想在调用 API(我这样做)之前放置一个加载小部件,然后我想在导入专辑后立即停止加载小部件。但是我该如何检查呢?
猜你喜欢
  • 2018-03-30
  • 2020-09-17
  • 1970-01-01
  • 2020-11-15
  • 2014-07-15
  • 2021-08-27
  • 1970-01-01
  • 2020-07-17
  • 1970-01-01
相关资源
最近更新 更多