2017-10-17 21 views
-2

J'essaie de mon mieux d'éviter les rappels avec mon Node JS. Mais j'essaye de faire un grand nombre d'api-demandes et les insère dans ma base de données.Noeud JS Demande d'API en boucle

Mon problème ici (bien sûr) est que ma boucle for-up s'exécute et s'incrémente avant que je finisse ma demande et l'insertion de la base de données.

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 
} 

Si quelqu'un d'autre venir par cette question, je peux vraiment recommander ce blogpost que j'ai trouvé après avoir lu la réponse joshvermaire:

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

+0

Regardez dans async/await - ils vous permettront de faire une pause pendant que apicall est actif. – theGleep

+0

'i' incrémenter ne devrait pas causer de problème dans votre cas. Votre problème est probablement autre chose. –

Répondre

1

Je vous recommande d'utiliser quelque chose comme async.each . Ensuite, vous pouvez faire:

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); 
} 

Lorsque la méthode dbInsert est terminée, assurez-vous que le rappel cb est appelée. Si vous devez le faire en série, regardez async.eachSeries.

+0

Comment cela résoudrait le problème de l'utilisateur si? et quel est exactement le problème de l'utilisateur? –

1

Il existe plusieurs façons d'aborder ce type de problème. Premièrement, si vous pouvez exécuter tous les appels d'API en parallèle (tout en vol en même temps) et peu importe l'ordre dans lequel ils sont insérés dans votre base de données, vous pouvez obtenir un résultat beaucoup plus rapidement (vs en les sérialisant dans l'ordre).

Dans toutes les options ci-dessous, vous pouvez utiliser ce code:

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 
} 

parallèle à l'aide ES6 standard promesses

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 
}); 

parallèle à l'aide Bluebird Promise Library

Avec la Bibliothèque Bluebird Promise, vous pouvez utiliser Promise.map() pour itérer votre tableau et vous pouvez lui passer l'option concurrency pour contrôler combien d'appels asynchrones sont en cours en même temps, ce qui pourrait éviter de surcharger la base de données ou l'hôte API cible et pourrait aider à contrôler l'utilisation maximale de la mémoire.

Promise.map(data, apiCall, {concurrency: 10}).then(() => { 
    // all done here 
}).catch(err => { 
    // error here 
}); 

Dans la série en utilisant la norme ES6 promesses

Si vous devez sérialisation pour une raison quelconque, comme l'insertion dans la base de données afin, alors vous pouvez le faire comme ça. Le schéma .reduce() illustré ci-dessous est un moyen classique pour sérialiser opérations de promesse sur un tableau en utilisant ES6 standard:

data.reduce(data, (p, item) => { 
    return p.then(() => { 
     return apicall(item); 
    }); 
}, Promise.resolve()).then(() => { 
    // all done here 
}).catch(err => { 
    // error here 
}); 

Dans la série utilisant Bluebird promesses

Bluebird a une Promise.mapSeries() qui itère un tableau en série, appelant une fonction qui renvoie une promesse sur chaque élément du tableau, ce qui est un peu plus simple que de le faire manuellement.

Promise.mapSeries(data, apiCall).then(() => { 
    // all done here 
}).catch(err => { 
    // error here 
});