Nodejs同步对于每个循环

use*_*415 17 javascript mysql synchronous node.js

我想为每个循环做一个但是让它同步运行.循环的每次迭代都将执行一次http.get调用,并返回json,以便将值插入数据库.问题是for循环以异步方式运行,导致所有http.gets都立即运行,我的数据库最终没有插入所有数据.我正在使用async-foreach尝试做我想做的事情它可以做,但如果我能以正确的方式做到这一点,我就不必使用它.

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);
        });
      });
    });
  });
});
});
Run Code Online (Sandbox Code Playgroud)

和我的模特

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);
};
Run Code Online (Sandbox Code Playgroud)

Ale*_*xMA 51

使用递归代码非常干净.等待http响应返回然后触发下一次尝试.我不认为for-each是最好的方法.

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);
Run Code Online (Sandbox Code Playgroud)

最后一点:这只是解决这个问题的一种方法.使用promises的解决方案也可以很好地工作,并且可以与许多有助于管理异步操作调度的面向承诺的库兼容.


Den*_*ret 5

要循环和同步链接异步操作,最干净的解决方案可能是使用promise库(在ES6中引入了承诺,这是要走的路).

使用Bluebird,这可能是

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
});
Run Code Online (Sandbox Code Playgroud)


use*_*415 2

我发现在完成每次调用后我没有释放我的 mysql 连接,这会占用连接,导致它失败,并且似乎是同步问题。

显式调用它后connection.release();,即使以异步方式,我的代码也能 100% 正确工作。

感谢那些提出这个问题的人。

  • 请注意,JavaScript 不提供尾递归,并且仅当递归深度有硬性限制时才应使用递归函数。如果你不知道这意味着什么并且你知道你会有很多循环,那就用承诺吧:) (2认同)