如何使用jQuery递延的功能,而不是async.waterfall? [英] How to use jQuery Deferred functionality instead of async.waterfall?
问题描述
我的函数调用链和async.waterfall使用。它的工作原理就像一个魅力。但我想这样做与jQuery推迟。如何将我的code?
从jQuery的网站的例子是这样的。这两种结果传递给完成
功能:
$。当($阿贾克斯(/page1.php),$。阿贾克斯(/page2.php)).done(功能(A1,A2){
// A1和A2解决的第一页和第二页Ajax请求的参数,分别为。
//每个参数是用以下结构的数组:[数据,状态文本,jqXHR]
VAR数据= A1 [0] + A2 [0]; // A1 [0] =鞭,A2 [0] =它
如果(/鞭/ .TEST(数据)){
警报(我们得到了我们来抓!);
}
});
但我的code是不同的。我需要一个回调传递给了瀑布
的每一步,我有如果
S IN回调。如何用jQuery实现它?这可能吗?
async.waterfall([
功能(CB){
VK.Api.call('users.get',{user_ids:res.session.mid,字段:田},功能(userDataRes){
CB(NULL,userDataRes);
});
},
功能(userDataRes,CB){
如果(userDataRes.response [0]。市){
VK.Api.call('database.getCitiesById',{city_ids:userDataRes.response [0]。城市},功能(cityDataRes){
CB(NULL,userDataRes,{城市:cityDataRes.response [0]。名称});
});
}
其他{
CB(NULL,userDataRes,{});
}
},
功能(userDataRes,cityDataRes,CB){
如果(userDataRes.response [0] .country){
VK.Api.call(database.getCountriesById,{country_ids:userDataRes.response [0] .country},功能(countryDataRes){
CB(NULL,userDataRes,cityDataRes,{国家:countryDataRes.response [0]。名称});
});
}
其他{
CB(NULL,userDataRes,{},{});
}
},
功能(userDataRes,cityDataRes,countryDataRes,CB){
VAR resObj = $ .extend(真{} userDataRes.response [0],cityDataRes,countryDataRes);
CB(NULL,resObj);
},
]
功能(ERR,RES){
的console.log(RES :::,RES);
}
);
UPD 1:
所以,我已经实现了一个解决方案,但预期它不工作。有一个在。然后()
和jQuery递延流异步API函数调用有破损。我不知道如何做一个。然后()
函数作为API的回调。
VAR DFR = $ .Deferred();dfr.then(功能(VAL){ //这是一个异步API函数调用。而其回调返回结果传递到下一个。那么()
//但是jQuery的递延流不遵循此API调用。
//它一起去到下一个。那么忽略此API调用。
//如何使它进入这个API调用,并从一个API的回调返回。
VK.Api.call('users.get',{user_ids:res.session.mid,字段:田},功能(userDataRes){
// CB(NULL,userDataRes);
的console.log(countryDataRes:,userDataRes);
返回userDataRes;
});
})。
然后(功能(userDataRes){
的console.log(countryDataRes:,userDataRes);
如果(userDataRes.response [0]。市){
VK.Api.call('database.getCitiesById',{city_ids:userDataRes.response [0]。城市},功能(cityDataRes){
// CB(NULL,userDataRes,{城市:cityDataRes.response [0]。名称});
返回[userDataRes,{城市:cityDataRes.response [0]。名称}];
});
}
其他{
// CB(NULL,userDataRes,{});
返回[userDataRes,{}];
}
})。
然后(功能(ARES){
如果(ARES [0] .response [0] .country){
VK.Api.call(database.getCountriesById,{country_ids:战神[0] .response [0] .country},功能(countryDataRes){
// CB(NULL,userDataRes,cityDataRes,{国家:countryDataRes.response [0]。名称});
返回[战神[0],战神[1],{国家:countryDataRes.response [0]。名称}];
});
}
其他{
CB(NULL,战神[0],{},{});
}
})。
然后(功能(ARES){
VAR resObj = $ .extend(真{}战神[0] .response [0],战神[1],战神[2]);
的console.log(cityDataRes:战神[1]);
的console.log(countryDataRes:ARES [2]);
CB(NULL,resObj);
返回resObj;
})。
完成(功能(RES){
的console.log(RES :::,RES);
});dfr.resolve();
让我们先从一般规则使用承诺:
每一个函数,做一些异步必须返回一个承诺
块引用>哪些功能这些都是你的情况?基本上,完整的瀑布,每年的花瀑布功能的
CB
和VK.Api.call
。嗯,
VK.Api.call
不返回的承诺,这是一个库函数,所以我们不能修改它。第2条进场:
块引用>在我们的例子中,它看起来是这样的:
函数callApi(方法,数据){
变种DFR = $ .Deferred();
VK.Api.call(方法,数据,功能(结果){
dfr.resolve(结果);
});
//没有错误回调?那真可怕!
//如果它提供的,调用`dfr.reject(ERR)`从中
返回dfr.promise();
}现在我们只承诺左右,也不再需要任何deferreds。第三条规则发挥作用的:
文件做一些事与异步结果一切都进入一个
。然后
回调
...并返回其结果。
块引用>这结果很可能会成为一个承诺不是一个普通值,
。然后
可以处理这些 - 并将给我们回用于执行的最终结果的新承诺东西。所以,让我们有些链则()
取值:apiCall('users.get',{user_ids:res.session.mid,字段:域})
。然后(功能(userDataRes){
的console.log(countryDataRes:,userDataRes);
如果(userDataRes.response [0]。市){
返回apiCall('database.getCitiesById',{city_ids:userDataRes.response [0]。市})
。然后(功能(cityDataRes){
返回[userDataRes,{城市:cityDataRes.response [0]。名称}];
});
}其他{
返回[userDataRes,{}];
}
})
。然后(功能(ARES){
如果(ARES [0] .response [0] .country){
返回apiCall(database.getCountriesById,{country_ids:战神[0] .response [0] .country})
。然后(功能(countryDataRes){
返回[战神[0],战神[1],{国家:countryDataRes.response [0]。名称}];
});
}其他{
返回[战神[0],战神[1],{}];
}
})
。然后(功能(ARES){
VAR resObj = $ .extend(真{}战神[0] .response [0],战神[1],战神[2]);
的console.log(cityDataRes:战神[1]);
的console.log(countryDataRes:ARES [2]);
返回resObj;
})
.done(功能(RES){
的console.log(RES :::,RES);
});至少,这是你原来的瀑布做了什么。让我们通过执行
getCitiesById
和getCountriesById
并行和删除明确创建这些所有的样板,把它擦亮了一下战神
数组。函数callApi(方法,数据){
变种DFR = $ .Deferred();
VK.Api.call(方法,数据,功能(结果){
dfr.resolve(result.response [0]);
//改变:^^^^^^^^^^^^
});
//没有错误回调?那真可怕!
//如果它提供的,调用`dfr.reject(ERR)`从中
返回dfr.promise();
}
apiCall('users.get',{user_ids:res.session.mid,字段:域})
。然后(功能(用户数据){
如果(userData.city)
变种cityProm = apiCall('database.getCitiesById',{city_ids:userData.city});
如果(userData.country)
变种countryProm = apiCall(database.getCountriesById,{country_ids:userData.country});
返回$。当(cityProm,countrProm)。然后(函数(城市,国家){
VAR resObj = $ .extend(真{}用户数据);
如果(市)
resObj.city = city.name;
如果(国家)
resObj.country = country.name;
返回resObj;
});
})
.done(功能(RES){
的console.log(RES :::,RES);
});I have a chain of function calls and use async.waterfall. It works like a charm. But I'd like to do it with jQuery Deferred. How to transform my code?
The example from jQuery site is like this. Both results are passed to
done
function:$.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!" ); } });
But my code is different. I need to pass a callback to every step of a
waterfall
and I haveif
s in callbacks. How to implement it with jQuery? Is it possible?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:
So, I've implemented a solution, but it doesn't work as expected. There is an asynchronous API function call in
.then()
and jQuery deferred flow is broken there. I don't know how to make a.then()
function as an API callback.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();
解决方案Let's start with the general rule for using promises:
Every function that does something asynchronous must return a promise
Which functions are these in your case? Basically, the complete waterfall, each of the waterfall functions that took a
cb
andVK.Api.call
.Hm,
VK.Api.call
doesn't return a promise, and it's a library function so we cannot modify it. Rule 2 comes into play:Create an immediate wrapper for every function that doesn't
In our case, it will look like this:
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(); }
Now we have only promises around, and do no more need any deferreds. Third rule comes into play:
Everything that does something with an async result goes into a
.then
callback…and returns its result.
That result might as well be a promise not a plain value,
.then
can handle these - and will give us back a new promise for the eventual result of executing the "something". So, let's chain somethen()
s: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); });
At least, that's what your original waterfall did. Let's polish it up a bit by executing
getCitiesById
andgetCountriesById
in parallel, and removing all the boilerplate of explicitly creating theseaRes
arrays.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); });
这篇关于如何使用jQuery递延的功能,而不是async.waterfall?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!