2017-02-07 4 views
-1

이렇게 많은 문제를 해결하고 벽에 머리를 두드리는 중입니다. 대부분의 경우, 나는 약속들과 그것들이 어떻게 작동 하는지를 잘 알고 있으며, 몇 가지 프로젝트에서 그것들을 사용했다. Google 캘린더 API에서 다른 캘린더 데이터를 여러 번 호출하고 스크립트가 콜백 함수에 사용할 결과 배열의 길이를 계산할 때 내 약속을 모두 지키는 데 약간의 문제가 있습니다. 내가 완료해야 약속의 배열을 기다리고로 jQuery가 지연된 약속으로 예상대로 작동하지 않을 때

(function($){ 
    var baseUrl = 'https://www.googleapis.com/calendar/v3/calendars/', 
     apiKey = 'xxxxxxxxxxxx', 
     calendarData = [], 
     events = [], 
     allCalendars = [], 
     eventsToDisplay = 9; 

    /* Get all the calendars that we have registered */ 
    function getCalendars() { 
     return $.getJSON(ajaxurl, {action: 'wps_get_calendars'}); 
    } 

    /* Get the events for a calendar by the calendar ID */ 
    function getCalendarEvents(calendarID) { 
     return $.getJSON(baseUrl + calendarID + '/events', { 
      maxResults: '4', 
      orderBy: 'startTime', 
      timeMin: moment().format(), 
      singleEvents: true, 
      key: apiKey 
     }).success(function(data){ 
      calendarData.push(data.items); 
    }); 

    /* Create a collection of promises */ 
    var promises = getCalendars().then(function(calendars){ 
     var deferreds = []; 
     calendars.forEach(function(calendar){ 
      deferreds.push( 
       getCalendarEvents(calendar.googleCalendarId) 
      ); 
     }); 
     return deferreds; 
    }); 

    /* Wait until all the promises have completed, then sort the events */ 
    $.when.apply($, promises).then(concatEvents); 

})(jQuery); 

은 기본적으로 문제가 $.when에 매우 마지막 호출에있다 : 여기에 관련 코드입니다. $.when$.when 콜백의 콘솔에 calendarData 배열을 기록하려고하면 계산 된 길이가없는 배열을 반환하기 때문에 작동하지 않는 것 같습니다. 이 작업을 수행하는 방법을 파악할 수있는 유일한 방법은 콜백에 setTimeout을 사용하고 약 2000 밀리 초로 설정하는 것입니다.하지만 네트워크 연결, API 가용성 등에 따라 이상적이지 않습니다. 모든 데이터를 수신 할 시간은 완전히 다를 수 있습니다.

$.when 콜백에 결과를 로깅하려고하면 콘솔에서 볼 수있는 아이디어와 마찬가지로 스크립트가 보이기 때문에 반복 할 수 없습니다. 비어 생각합니다 :

array with no length

어떤 생각을 내가 잘못 여기서 뭘하는지? 모든 도움을 미리 감사드립니다.

+0

1) deferred.then는 반환 된 배열이 아니라 새로운 약속을 반환합니다. 2) getcalendars가 해결 될 때까지는 배열에 액세스 할 수 없습니다. 3) .then의 범위 밖에서 약속 배열을 만들고 getcalendars.then을 사용하여 그것을 채 웁니다. getcalendars에서 해결할 다른 외부 지연을 사용하십시오. 최종 약속이 배열로 푸시 된 다음 배열을 사용하여 .apply를 수행합니다. –

+0

'$ .when()'은 실제로 뇌사 상태입니다. jQuery Ajax가 호출된다. 배열로 해석되지 않습니다. N 개의 개별 인수로 해석되며 각 인수는 배열 일 수 있습니다. 임의의 수의 결과를 처리하려면'$ .when (...), then (fn)'에'fn'에 전달 된'arguments' 객체를 처리해야합니다. jQuery 문서에서'$ .when()'예제를 공부하십시오. 특히 Ajax 호출과 함께 사용할 때 더욱 그렇습니다. – jfriend00

답변

0

코드가 작동하는 방식에 몇 가지 구조적인 문제가있었습니다. 내가 식별 한 문제 :

  1. 더 이상 사용되지 않는 .success()을 사용하지 마십시오. .then()을 사용하십시오.
  2. 약속에서 일련의 약속을 반환하려고했습니다. 대신 $.when()을 사용하면 결과 배열로 해석되는 단일 약속을 반환 할 수 있습니다.
  3. $.when()은 결과를 반환하는 방식에 꽤 어색합니다. 결과 배열이 아닌 별도의 인수로 반환합니다 (ES6 표준 Promise.all()처럼 작동하지 않습니다).
  4. jQuery Ajax 호출은 세 가지 인수를 해결하고 $.when()으로 직접 jQuery ajax를 사용하면 $.when()으로 매우 이상하게 상호 작용합니다.
  5. 원하는 데이터로 약속을 해결하는 것보다 상위 범위의 변수에서 부작용을 사용하고있었습니다 (데이터를 추적하는 상위 범위 변수가 필요하지 않음). 이로 인해 코드가 훨씬 더 자급하고 재개 가능하며 경쟁 조건 (두 개 이상의 장소에서 사용되는 경우)이 적용되지 않습니다.
  6. 구조체 getCalendar() 그래서 일정 배열로 해석되는 단일 약속을 반환하므로 훨씬 간단하게 사용할 수 있습니다.

이것은 원하는 결과를 얻고 더 높은 범위의 변수 및 부작용을 제거합니다.

(function($){ 
    var baseUrl = 'https://www.googleapis.com/calendar/v3/calendars/', 
     apiKey = 'xxxxxxxxxxxx', 
     events = [], 
     eventsToDisplay = 9; 

    /* Get all the calendars that we have registered */ 
    function getCalendars() { 
     return $.getJSON(ajaxurl, {action: 'wps_get_calendars'}).then(function(calendars){ 
      var promises = calendars.map(function(calendar) { 
       return getCalendarEvents(calendar.googleCalendarId); 
      }); 
      return $.when.apply($, promises).then(function() { 
       // convert arguments to a single array as our resolved value 
       return [].slice.call(arguments); 
      }); 
     }); 
    } 

    /* Get the events for a calendar by the calendar ID */ 
    function getCalendarEvents(calendarID) { 
     return $.getJSON(baseUrl + calendarID + '/events', { 
      maxResults: '4', 
      orderBy: 'startTime', 
      timeMin: moment().format(), 
      singleEvents: true, 
      key: apiKey 
     }).then(function(data){ 
      // make resolved value be just data.items 
      return data.items; 
    }); 

    /* get all calendars */ 
    getCalendars().then(function(calendars){ 
     // process array of calendars here 
     console.log(calendars); 
    }); 

})(jQuery); 
또한

, 어떻게 $.when() 작품으로 혼동하기가 매우 쉽습니다. 설명 할 수있는 몇 가지 일반적인 정보가 있습니다.

$.when() 결과 배열로 해결되지 않습니다. 대신 각 결과를 별도의 인수로 콜백에 전달합니다. 당신이 세 가지 결과를 경우에 따라서, 다음이 작업을 수행합니다 :

$.when(p1, p2, p3).then(function(r1, r2, r3) { 
    console.log(r1, r2, r3); 
}); 

다음, jQuery를 AJAX 호출이 중 하나의 값으로 해결되지 않는 그 위에, 그것은 세 가지 값을 해결합니다. 따라서 N jQuery ajax를 전달하면 $.when(), 콜백에 N 개의 인수가 있습니다. 각 인수는 세 개의 값 (jQuery Ajax 약속의 세 값)의 배열입니다. 당신이 $.when()에 약속 결과의 임의의 수를 처리 할 경우


그래서, 당신은 당신의 콜백에 전달 된 arguments 개체를 사용하고를 반복해야합니다. 당신이 그것에 정상적인 배열 기능을 사용할 수 있도록

function processWhenResults() { 
    for (var i = 0; i < arguments.length; i++) { 
     // output each ajax result 
     // arguments[i] is an array of results for each corresponding ajax call 
     // arguments[i][0] is the actual Ajax result value 
     console.log(arguments[i][0]); 
    } 
} 


$.when.apply($, promises).then(processWhenResults); 

또는, 당신은 내가 위의 내 제안 코드에서처럼 수행하고 인수를 변환 할 수 있습니다 결과의 배열에 반대.


또한 .success()은 더 이상 사용되지 않습니다. 당신은 그것을 사용해서는 안됩니다. 대신 .then()을 사용하십시오.

+0

왜 downvote? 설명 해주십시오. – jfriend00

+0

코딩 로직의 구조적 문제에 중요한 추가 정보가 추가되었습니다. – jfriend00

+0

@brianjohnhanna -이게 당신에게 필요한 것을 설명하고 질문에 대답 했습니까? – jfriend00

-2

조금만 가지고 놀아 본 적이 없지만 이것을 가져 가서 실행할 수는 있습니다.

/* Create a collection of promises */ 
var control = $.Deferred(); 
var deferreds = []; 
getcalendars().done(function(calendars){ 
    calendars.forEach(function(calendar){ 
     deferreds.push( 
      getCalendarEvents(calendar.googleCalendarId) 
     ); 
    }); 
    control.resolve(); 
}); 

control.done(function(){ 
    /* Wait until all the promises have completed, then sort the events */ 
    $.when.apply($, deferreds).done(function() {concatEvents}); }) 
+1

이 문제가 어떻게 해결됩니까? – jfriend00

+0

그가 약속을 지키기 전에 모든 약속이 그대로 유지되기 때문에. 모든 약속이 배열에 들어간 후에 만 ​​설정이 완료됩니다. 그리고 deferreds []는 이제 접근 할 수있는 범위에 있습니다. –