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);
};
各呼び出しが終了した後、mysql接続を解放していないことがわかりました。これにより、接続が拘束されて失敗し、同期の問題のように見えます。
connection.release();
を明示的に呼び出した後、非同期方式でもコードが100%正しく動作するようになりました。
この質問に投稿してくれた人に感謝します。
再帰を使用すると、コードはかなりきれいになります。 http応答が戻るのを待ってから、次の試行を開始します。これは、ノードのすべてのバージョンで機能します。
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);
Promiseを使用したソリューションもうまく機能し、より簡潔になります。たとえば、 promiseを返すgetのバージョン およびNode v7.6 +がある場合、この例のようなasync/await関数を記述できます。いくつかの新しいJS機能を使用します。
const urls = ['http://stackoverflow.com/', 'http://security.stackexchange.com/', 'http://unix.stackexchange.com/'];
async function processItems(urls){
for(const url of urls) {
const response = await promisifiedHttpGet(url);
// add some code here to process the response.
}
};
processItems(urls);
注:これらの例はどちらもエラー処理をスキップしますが、実稼働アプリではおそらくそれが必要です。
非同期アクションをループして同期的にチェーンするための最もクリーンなソリューションは、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
});
"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);
});
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
});
}