簡體   English   中英

循環中的節點JS Api請求

[英]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的回復后發現的:

http://www.sebastianseilund.com/nodejs-async-in-practice

有很多方法可以解決此類問題。 首先,如果您可以並行運行所有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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM