[英]Node JS Api request in loop
我正在盡我最大的努力避免使用Node JS造成回調地獄。 但是我正在嘗試進行大量的api請求,並將它們插入到我的數據庫中。
我的問題(當然)是我的for循環在完成請求和數據庫插入之前運行並遞增i。
for(var i = 0; i <= 1 ; i++){
apiRequest = data[i];
apicall(apiRequest);
}
function apicall(urlApi){
request((urlApi), function(error, response, body){
if(error){
console.log("error");
} else if(!error && response.statusCode == 200){
var myobj = JSON.parse(body);
dbInsert(myobj);
}
});
}
function dbInsert(obj) {
//insert into database
}
如果有人會問這個問題,我可以真正推薦這篇博文,是在閱讀joshvermaire的回復后發現的:
有很多方法可以解決此類問題。 首先,如果您可以並行運行所有API調用(全部同時運行),並且將它們插入數據庫的順序無關緊要,那么這樣做可以更快地得到結果(vs 。按順序序列化它們)。
在下面的所有選項中,您將使用以下代碼:
const rp = require('request-promise');
function apicall(urlApi){
return rp({url: urlApi, json: true}).then(function(obj){
return dbInsert(obj);
});
}
function dbInsert(obj) {
//insert into database
// return a promise that resolves when the database insertion is done
}
並行使用ES6標准承諾
let promises = [];
for (let i = 0; i <= data.length; i++) {
promises.push(apicall(data[i]));
}
Promise.all(promises).then(() => {
// all done here
}).catch(err => {
// error here
});
並行使用Bluebird Promise庫
使用Bluebird Promise庫,您可以使用Promise.map()
來迭代數組,並可以將concurrency
選項傳遞給它,以控制concurrency
進行的異步調用數量,以免使數據庫或目標不堪重負API主機,可能有助於控制最大內存使用量。
Promise.map(data, apiCall, {concurrency: 10}).then(() => {
// all done here
}).catch(err => {
// error here
});
使用標准ES6承諾的系列內
如果由於某種原因(例如按順序插入數據庫)必須序列化它們,則可以這樣進行。 下面顯示的.reduce()
模式是使用標准ES6對數組上的promise操作進行序列化的經典方法:
data.reduce(data, (p, item) => {
return p.then(() => {
return apicall(item);
});
}, Promise.resolve()).then(() => {
// all done here
}).catch(err => {
// error here
});
在系列中使用Bluebird的承諾
藍鳥有一個Promise.mapSeries()
,它可以Promise.mapSeries()
迭代一個數組,並調用一個函數,該函數對數組中的每個項目返回一個promise,這比手動完成要簡單一些。
Promise.mapSeries(data, apiCall).then(() => {
// all done here
}).catch(err => {
// error here
});
我建議使用async.each之類的東西 。 然后,您可以執行以下操作:
async.each(data, function(apiRequest, cb) {
apicall(apiRequest, cb);
}, function(err) {
// do something after all api requests have been made
});
function apicall(urlApi, cb){
request((urlApi), function(error, response, body){
if(error){
console.log("error");
cb(error);
} else if(!error && response.statusCode == 200){
var myobj = JSON.parse(body);
dbInsert(myobj, cb);
}
});
}
function dbInsert(obj, cb) {
doDBInsert(obj, cb);
}
dbInsert
方法完成后,請確保調用了cb
回調。 如果需要按系列進行此操作,請查看async.eachSeries
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.