2014-11-14 2 views
0

Я все время ударил головой в стену, потому что я не могу заставить следующий код работать. Я пытаюсь закодировать фотогалерею с помощью flickrApi и иметь проблемы с несколькими асинхронными вызовами. Но, возможно, есть более чистое решение, чтобы закодировать это.flickrapi (js) несколько асинхронных вызовов в цикле

openPhotoset() вызывается при нажатии ссылки на фотосет. К сожалению, для получения описания фотографии мне нужно использовать другой метод, что означает другой асинхронный вызов. Я перебираю данные, но потому, что я делаю вызов в цикле (это когда у меня есть доступный идентификатор фото), отложенная функция openPhotoset() не решает после цикла, но раньше. Я читал и видел примеры $ .when(), используемые в цикле, заполняя массив отсрочками и проверяя с помощью $ .when, но я, похоже, ужасно терпеть неудачу. Это решение, в котором я нуждаюсь, или есть еще один путь к спасению? ;)

Я хочу выполнить различные функции после того, как все вызовы в openPhotoset() завершены.

 function openPhotoset(photosetId) { 
      var currentPhotoset = [], 
       deferred = $.Deferred(); 

      _requestPhotosOfSet(photosetId).done(function(data){ 
       $(data.photoset.photo).each(function(i, photo){ 
        var objPhoto = {}; 

        objPhoto.id = photo.id; 
        objPhoto.title = photo.title; 
        objPhoto.farm = photo.farm; 
        objPhoto.server = photo.server; 
        objPhoto.secret = photo.secret; 

        // get photo description 
        requestPhotoInfo(photo.id).done(function(data) { 

         objPhoto.description = data.photo.description._content; 
         currentPhotoset.push(objPhoto); 

        }).then(function() { 
         // TODO: renders with each iteration, shouldnt! 
         var template = $('#li-gallery').html(), 
          result = Mustache.render(template, {currentPhotoset:currentPhotoset}); 

         showGallery(); 
         _$fyGallery.find('.gallery-list').html(result); 

         deferred.resolve(); 

        }); 
       }); 

      }); 

      return deferred; 

     } 

ответ

1

Вы можете сделать это, изменив .done() на .then() в нескольких местах и ​​немного переставив вещи - ну совсем много.

Я думаю, что вы, вероятно, искал что-то вроде этого:

function openPhotoset(photosetId) { 
    return _requestPhotosOfSet(photosetId).then(function(data) { 
     var promises = $(data.photoset.photo).map(function(photo) { 
      return requestPhotoInfo(photo.id).then(function(data) { 
       return { 
        id: photo.id, 
        title: photo.title, 
        farm: photo.farm, 
        server: photo.server, 
        secret: photo.secret, 
        description: data.photo.description._content 
       }; 
      }); 
     }).get();//.get() is necessary to convert a jQuery object to a regular js array. 
     return $.when.apply(null, promises).then(function() { 
      var template = $('#li-gallery').html(), 
       result = Mustache.render(template, { 
        currentPhotoset: Array.prototype.slice.apply(arguments) 
       }); 
      showGallery(); 
      _$fyGallery.find('.gallery-list').html(result); 
     }); 
    }); 
} 

Основное отличие заключается в создании массива обещаний, в отличие от массива объектов фотографии и позволяя обещания передавать данные. Это позволяет $.when() отменить обратный вызов, когда выполняются все обещания, т. Е. Когда объекты данных были составлены для всех фотографий в наборе.

Обратите внимание на использование .map() вместо .each(), что упрощает создание promises.

И, наконец, общее обещание, возвращенное openPhotoset(), позволяет любые действия, которые необходимо предпринять по завершении всего процесса. Просто цепь .then().

openPhotoset(...).then(function() { 
    // here, do whatever 
}); 

EDIT

Общая картина, вероятно, легче понять, если внутренние работы вытащены и перефразировать как именованные обещание функций, возвращающих - getPhotoInfoObject() и renderData().

function openPhotoset(photosetId) { 
    function getPhotoInfoObject(photo) { 
     return requestPhotoInfo(photo.id).then(function(data) { 
      //$.extend() is much less verbose than copying `photo`'s properties into a new object longhand. 
      return $.extend(photo, {description: data.photo.description._content}); 
     }); 
    } 
    function renderData() { 
     var template = $('#li-gallery').html(), 
      currentPhotoset = Array.prototype.slice.apply(arguments), 
      result = Mustache.render(template, { 
       currentPhotoset: currentPhotoset 
      }); 
     showGallery(); 
     _$fyGallery.find('.gallery-list').html(result); 
    } 
    // With the inner workings pulled out as getPhotoInfoObject() and renderData(), 
    // the residual pattern is very concise and easier to understand. 
    return _requestPhotosOfSet(photosetId).then(function(data) { 
     var promises = $(data.photoset.photo).map(getPhotoInfoObject).get(); 
     return $.when.apply(null, promises).then(renderData); 
    }); 
} 
+0

спасибо за ответ @ Roamer-1888 Я действительно искал это. Спасибо, что показал мне другой способ приблизиться к этому. Мне все еще трудно понять значение $ .when.apply (null, promises), так как я не уверен, что требуется .apply (null, promises). Мое предположение - это массив обещаний, которые $ .when могут прокручивать и возвращать обещание «мастера»? Кроме того, почему нулевой параметр? Я прочитал в приложении (javascriptissexy.com, но, похоже, не понял его.) – flowen

+0

Flowen, '.apply()' '.call()' и '.bind()' связаны с методами js Function. Все три принимают «контекст» в качестве своего первого параметра - то есть объект, который будет использоваться как «это» в целевой функции.Если у целевой функции нет 'this' (в ее непосредственной области), тогда контекст не требуется, но первый слот параметра все равно должен быть занят, поэтому вы можете передать 'null'. У jQuery '$ .when()' есть слабость в том, что он принимает только обычные параметры, разделенные запятыми, тогда как во многих случаях мы хотели бы передать массив. Выполняя '$ .when.apply (null, array)', мы преодолеваем это ограничение. –

+0

Я добавил раздел, чтобы попытаться объяснить шаблон, используемый в ответе. –

0

Я был настолько ослеплен defereds и $ .when функция, я не заметил, все, что мне было нужно, чтобы создать счетчик и отсчитывать каждый раз, когда requestPhotoInfo было сделано, и после визуализации HTML

Смежные вопросы