web-dev-qa-db-fra.com

Nodejs Synchronous Pour chaque boucle

Je veux faire une boucle pour chaque boucle mais la faire fonctionner de manière synchrone. Chaque itération de la boucle effectuera un appel http.get et renvoyera json pour qu’elle insère les valeurs dans une base de données. Le problème est que la boucle for s'exécute de manière asynchrone et que tous les http.gets sont exécutés en même temps et que ma base de données ne finit pas par insérer toutes les données. J'utilise async-foreach pour essayer de faire ce que je veux. faire, mais je n’ai pas à l’utiliser si je peux le faire correctement.

mCardImport = require('m_cardImport.js');
var http = require('http');
app.get('/path/hi', function(req, res) {

mCardImport.getList(function(sets) {
  forEach(sets, function(item, index, arr) {
    theUrl = 'http://' + sets.set_code + '.json';
    http.get(theUrl, function(res) {

      var jsonData = '';
      res.on('data', function(chunk) {
        jsonData += chunk;
      });

      res.on('end', function() {
        var theResponse = JSON.parse(jsonData);
        mCardImport.importResponse(theResponse.list, theResponse.code, function(theSet) {
          console.log("SET: " + theSet);
        });
      });
    });
  });
});
});

et mon modèle

exports.importResponse = function(cardList, setCode, callback) {

mysqlLib.getConnection(function(err, connection) {

forEach(cardList, function(item, index, arr) {

  var theSql = "INSERT INTO table (name, code, multid, collector_set_num) VALUES "
   + "(?, ?, ?, ?) ON DUPLICATE KEY UPDATE id=id";
  connection.query(theSql, [item.name, setCode, item.multid, item.number], function(err, results) {
    if (err) {
      console.log(err);
    };
  });
});
});
callback(setCode);
};
14
user3447415

J'ai découvert que je ne libérais pas mes connexions mysql après chaque appel et que cela bloquait les connexions, ce qui entraînait un échec et un problème de synchronisation.

Après avoir explicitement appelé connection.release();, mon code a fonctionné à 100% correctement, même de manière asynchrone.

Merci à ceux qui ont posté sur cette question.

1
user3447415

Avec la récursivité, le code est assez propre. Attendez que la réponse http revienne, puis lancez la prochaine tentative. Je ne pense pas qu'un pour-chacun soit la meilleure approche.

var urls = ['http://stackoverflow.com/', 'http://security.stackexchange.com/', 'http://unix.stackexchange.com/'];

var processItems = function(x){
  if( x < urls.length ) {
    http.get(urls[x], function(res) {

      // add some code here to process the response

      processItems(x+1);
    });
  }
};

processItems(0);

Une dernière note: ce n’est qu’une approche pour résoudre ce problème. Une solution utilisant des promesses fonctionnerait également bien et serait compatible avec de nombreuses bibliothèques orientées promesse qui permettent de gérer la planification des opérations asynchrones.

43
AlexMA

Pour boucler et chaîner de manière synchrone des actions asynchrones, la solution la plus propre consiste probablement à utiliser une bibliothèque de promesses (des promesses sont introduites dans ES6, c’est la voie à suivre).

Utiliser Bluebird , cela pourrait être

Var p = Promise.resolve();
forEach(sets, function(item, index, arr) {
    p.then(new Promise(function(resolve, reject) {
         http.get(theUrl, function(res) {
         ....
         res.on('end', function() {
              ...
              resolve();
         }
    }));
});
p.then(function(){
   // all tasks launched in the loop are finished
});
5
Denys Séguret
"use strict";

var Promise = require("bluebird");
var some = require('promise-sequence/lib/some');

var pinger = function(wht) {
    return new Promise(function(resolve, reject) {
        setTimeout(function () { 

            console.log('I`ll Be Waiting: ' + wht);
            resolve(wht);

        }, Math.random() * (2000 - 1500) + 1500);
    });
}

var result = [];
for (var i = 0; i <= 12; i++) {
    result.Push(i);
}

some(result, pinger).then(function(result){
  console.log(result);
});
0
user956584
var urls = ['http://stackoverflow.com/', 'http://security.stackexchange.com/', 'http://unix.stackexchange.com/'];

for (i = 0; i < urls.length; i++){
   http.get(urls[i], function(res) {
       // add some code here to process the response
   });
}
0
RAHUL.S