2014-09-08 5 views
1

나는 일련의 함수 호출을 가지고 있고 async.waterfall을 사용한다. 그것은 매력처럼 작동합니다. 하지만 jQuery Deferred로 해보고 싶습니다. 내 코드를 변환하는 방법?async.waterfall 대신 jQuery Deferred 기능을 사용하는 방법?

jQuery 사이트의 예는 다음과 같습니다. 두 결과는 done 함수에 전달됩니다

$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1, a2) { 
    // a1 and a2 are arguments resolved for the page1 and page2 ajax requests, respectively. 
    // Each argument is an array with the following structure: [ data, statusText, jqXHR ] 
    var data = a1[ 0 ] + a2[ 0 ]; // a1[ 0 ] = "Whip", a2[ 0 ] = " It" 
    if (/Whip It/.test(data)) { 
    alert("We got what we came for!"); 
    } 
}); 

하지만 내 코드는 다르다. waterfall의 모든 단계에 콜백을 전달해야하며 콜백에 if이 있습니다. jQuery로 구현하는 방법은 무엇입니까? 가능한가?

async.waterfall([ 
     function(cb) { 
      VK.Api.call('users.get', {user_ids: res.session.mid, fields: fields}, function(userDataRes) { 
       cb(null, userDataRes); 
      }); 
     }, 
     function(userDataRes, cb) { 
      if(userDataRes.response[0].city) { 
       VK.Api.call('database.getCitiesById', {city_ids: userDataRes.response[0].city}, function(cityDataRes) { 
        cb(null, userDataRes, {city: cityDataRes.response[0].name}); 
       }); 
      } 
      else { 
       cb(null, userDataRes, {}); 
      } 
     }, 
     function(userDataRes, cityDataRes, cb) { 
      if(userDataRes.response[0].country) { 
       VK.Api.call("database.getCountriesById", {country_ids: userDataRes.response[0].country}, function(countryDataRes) { 
        cb(null, userDataRes, cityDataRes, {country: countryDataRes.response[0].name}); 
       }); 
      } 
      else { 
       cb(null, userDataRes, {}, {}); 
      } 
     }, 
     function(userDataRes, cityDataRes, countryDataRes, cb) { 
      var resObj = $.extend(true, {}, userDataRes.response[0], cityDataRes, countryDataRes); 
      cb(null, resObj); 
     }, 
    ], 
    function(err, res) { 
     console.log("res::: ", res); 
    } 
); 

UPD 1 :

그래서, 나는 해결책을 구현했지만, 예상대로 작동하지 않습니다. .then()에 비동기식 API 함수 호출이 있으며 jQuery 지연된 플로우가 거기에서 중단되었습니다. .then() 함수를 API 콜백으로 만드는 방법을 모르겠습니다.

var dfr = $.Deferred(); 

dfr.then(function(val) { 

    // THIS is an asynchronous API function call. And its callback returns result that is passed to the next .then() 
    // But jQuery deferred flow doesn't follow this API call. 
    // It goes along to the next .then ignoring this API call. 
    // How to make it enter this API call and be returned from a API's callback. 
    VK.Api.call('users.get', {user_ids: res.session.mid, fields: fields}, function(userDataRes) { 
     // cb(null, userDataRes); 
     console.log("countryDataRes: ", userDataRes); 
     return userDataRes; 
    }); 
}). 
then(function(userDataRes) { 
    console.log("countryDataRes: ", userDataRes); 
    if(userDataRes.response[0].city) { 
     VK.Api.call('database.getCitiesById', {city_ids: userDataRes.response[0].city}, function(cityDataRes) { 
      // cb(null, userDataRes, {city: cityDataRes.response[0].name}); 
      return [userDataRes, {city: cityDataRes.response[0].name}]; 
     }); 
    } 
    else { 
     // cb(null, userDataRes, {}); 
     return [userDataRes, {}]; 
    } 
}). 
then(function(aRes) { 
    if(aRes[0].response[0].country) { 
     VK.Api.call("database.getCountriesById", {country_ids: aRes[0].response[0].country}, function(countryDataRes) { 
      // cb(null, userDataRes, cityDataRes, {country: countryDataRes.response[0].name}); 
      return [aRes[0], aRes[1], {country: countryDataRes.response[0].name}]; 
     }); 
    } 
    else { 
     cb(null, aRes[0], {}, {}); 
    } 
}). 
then(function(aRes) { 
    var resObj = $.extend(true, {}, aRes[0].response[0], aRes[1], aRes[2]); 
    console.log("cityDataRes: ", aRes[1]); 
    console.log("countryDataRes: ", aRes[2]); 
    cb(null, resObj); 
    return resObj; 
}). 
done(function(res) { 
    console.log("res::: ", res); 
}); 

dfr.resolve(); 
+0

@DevlshOne, 그게 내가 지금하려는 것입니다. 그러나 jQuery에는이 작업에 대한 구현 패러다임이 다릅니다. 그리고 나는 그것을 어떻게하는지 이해할 수 없다. 나는 준비된 결과, 단서를 요구하지 않고있다. 그러니 그 일에 대해 어떤 단서를 주시겠습니까? 아니면 비난을 치를 수 있습니까? – Green

+0

"단서"는 jQuery 팀이'.when()'메소드를 사용하는 방법에 대한 예제입니다. 그것을 구현하려는 시도를 보여 주면 비난이 줄어들 것입니다. – DevlshOne

답변

5

는 약속을 사용하는의는 일반적으로 시작하자 :

뭔가 비동기 약속 기능이 귀하의 경우이있다

을 반환해야 않습니다 모든 기능을? 기본적으로 전체 폭포는 각각 cbVK.Api.call을 사용하는 폭포 함수입니다.

흠, VK.Api.call은 약속을 반환하지 않으며 라이브러리 기능이므로 수정할 수 없습니다. 규칙 2가 활동하기 시작 : 우리의 경우

을하지 않는 모든 기능에

Create an immediate wrapper, 그것은 다음과 같이 표시됩니다

function callApi(method, data) { 
    var dfr = $.Deferred(); 
    VK.Api.call(method, data, function(result) { 
     dfr.resolve(result); 
    }); 
    // No error callbacks? That's scary! 
    // If it does offer one, call `dfr.reject(err)` from it 
    return dfr.promise(); 
} 

이제 우리는 약속을 더 이상 지연을 필요로하지 않습니다. 비동기 결과로 무언가를

모두가 .then 콜백

로 전환 ... 그 결과를 돌려 : 제 규칙은 놀이로 제공됩니다. 뿐만 아니라 약속이 아니라 일반 값이 될 수있는 결과

.then 다음을 처리 할 수 ​​-하고 "무언가를"실행의 최종 결과에 대한 새로운 약속을 우리에게 돌려 줄 것입니다. 그래서,하자 체인 일부 then()들 :

apiCall('users.get', {user_ids: res.session.mid, fields: fields}) 
.then(function(userDataRes) { 
    console.log("countryDataRes: ", userDataRes); 
    if (userDataRes.response[0].city) { 
     return apiCall('database.getCitiesById', {city_ids: userDataRes.response[0].city}) 
     .then(function(cityDataRes) { 
      return [userDataRes, {city: cityDataRes.response[0].name}]; 
     }); 
    } else { 
     return [userDataRes, {}]; 
    } 
}) 
.then(function(aRes) { 
    if (aRes[0].response[0].country) { 
     return apiCall("database.getCountriesById", {country_ids: aRes[0].response[0].country}) 
     .then(function(countryDataRes) { 
      return [aRes[0], aRes[1], {country: countryDataRes.response[0].name}]; 
     }); 
    } else { 
     return [aRes[0], aRes[1], {}]; 
    } 
}) 
.then(function(aRes) { 
    var resObj = $.extend(true, {}, aRes[0].response[0], aRes[1], aRes[2]); 
    console.log("cityDataRes: ", aRes[1]); 
    console.log("countryDataRes: ", aRes[2]); 
    return resObj; 
}) 
.done(function(res) { 
    console.log("res::: ", res); 
}); 

적어도, 그 원래의 폭포가 무슨 짓을했는지.getCitiesByIdgetCountriesById을 병렬로 실행하고 명시 적으로 이러한 aRes 배열을 생성하는 모든 상용구를 제거하여 조금씩 연마 해 봅시다.

function callApi(method, data) { 
    var dfr = $.Deferred(); 
    VK.Api.call(method, data, function(result) { 
     dfr.resolve(result.response[0]); 
//    changed: ^^^^^^^^^^^^ 
    }); 
    // No error callbacks? That's scary! 
    // If it does offer one, call `dfr.reject(err)` from it 
    return dfr.promise(); 
} 
apiCall('users.get', {user_ids: res.session.mid, fields: fields}) 
.then(function(userData) { 
    if (userData.city) 
     var cityProm = apiCall('database.getCitiesById', {city_ids: userData.city}); 
    if (userData.country) 
     var countryProm = apiCall("database.getCountriesById", {country_ids: userData.country}); 
    return $.when(cityProm, countrProm).then(function(city, country) { 
     var resObj = $.extend(true, {}, userData); 
     if (city) 
      resObj.city = city.name; 
     if (country) 
      resObj.country = country.name; 
     return resObj; 
    }); 
}) 
.done(function(res) { 
    console.log("res::: ", res); 
});