javascript domとは - 各ループについてノードノード同期




ノードとは dom操作 (5)

forループごとに実行したいのですが、同期的に実行させます。 ループが繰り返されるたびにhttp.getが呼び出され、データベースに値を挿入するためのjsonが返されます。 問題は、forループが非同期的に実行され、すべてのhttp.getsが一度に実行され、データベースがすべてのデータを挿入してしまうことがないことです。それはやることですが、正しい方法でできればそれを使う必要はありません。

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

そして私のモデル

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

Answers

非同期アクションをループさせ、同期的に連鎖させるには、最も賢明な解決策はおそらくpromiseライブラリを使用することです(ES6ではpromiseが導入されています。これが正しい方法です)。

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

再帰を使えば、コードはかなりきれいです。 http応答が戻ってくるのを待ってから、次の試行を開始してください。 私はfor-eachが最良のアプローチだとは思いません。

var urls = ['http://.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);

最後の注意点:これはこの問題を解決するための唯一の方法です。 プロミスを使用するソリューションもうまく機能し、非同期操作のスケジューリングの管理に役立つ多くのプロミス指向のライブラリと互換性があります。


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

私は各呼び出しを終えた後に私のmysql接続を解放していないことを知りました、そしてこれはそれが失敗する原因となっている接続を結び付け、同期の問題であるように見えます。

明示的にconnection.release();呼び出した後connection.release(); それは私のコードが非同期的に100%正しく動作する原因となりました。

この質問に投稿してくれた人に感謝します。


ソースを見ると、同期バージョンのpath.exists - path.existsSyncます。 それはドキュメントで見逃されたように見えます。

更新:

path.existspath.existsSync廃止予定ですfs.existsfs.existsSync使用してください

アップデート2016:

fs.existsfs.existsSync廃止予定です 。 代わりにfs.stat()またはfs.access()使用してください。





javascript mysql node.js synchronous