Javascript Node.js同步循环或迭代异步语句
我想为每个循环做一个测试,但是让它同步运行。循环的每个迭代都将执行一个http.get调用,该调用将返回json,以便将值插入数据库。问题是for循环是异步运行的,这会导致所有http.get同时运行,并且我的数据库不会插入所有数据。我使用async foreach尝试执行我希望它执行的操作,但如果我能够正确执行,我不必使用它Javascript Node.js同步循环或迭代异步语句,javascript,mysql,node.js,synchronous,Javascript,Mysql,Node.js,Synchronous,我想为每个循环做一个测试,但是让它同步运行。循环的每个迭代都将执行一个http.get调用,该调用将返回json,以便将值插入数据库。问题是for循环是异步运行的,这会导致所有http.get同时运行,并且我的数据库不会插入所有数据。我使用async foreach尝试执行我希望它执行的操作,但如果我能够正确执行,我不必使用它 mCardImport = require('m_cardImport.js'); var http = require('http'); app.get('/path/
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);
};
要循环并同步链接异步操作,最干净的解决方案可能是使用承诺库(承诺是在ES6中引入的,这是一种方法) 使用,这可能是
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响应返回,然后触发下一次尝试。这将适用于所有版本的节点
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);
注意:这两个示例都跳过了错误处理,但您可能应该在生产应用程序中使用错误处理。我发现在每次调用完成后,我没有释放mysql连接,这会导致连接阻塞,导致连接失败,并且似乎是同步问题 显式调用
connection.release()后代码>它使我的代码即使以异步方式也能100%正确工作
感谢大家发布此问题。“严格使用”;
"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承诺=要求(“蓝鸟”);
var some=require('promise-sequence/lib/some');
var pinger=功能(wht){
返回新承诺(功能(解决、拒绝){
setTimeout(函数(){
log('我将等待:'+wht);
解决(wht);
},Math.random()*(2000-1500)+1500);
});
}
var结果=[];
对于(var i=0;ivar url=['http://stackoverflow.com/', 'http://security.stackexchange.com/', 'http://unix.stackexchange.com/'];
对于(i=0;i
只需将循环包装在一个异步
函数中即可。此示例说明了我的意思:
const oneSecond = async () =>
new Promise((res, _) => setTimeout(res, 1000));
此函数仅在1秒后完成:
const syncFun = () => {
for (let i = 0; i < 5; i++) {
oneSecond().then(() => console.log(`${i}`));
}
}
syncFun(); // Completes after 1 second ❌
const syncFun=()=>{
for(设i=0;i<5;i++){
oneSecond().then(()=>console.log(`${i}`));
}
}
syncFun();//1秒后完成❌
这一个按预期工作,5秒后完成:
const asyncFun = async () => {
for (let i = 0; i < 5; i++) {
await oneSecond();
console.log(`${i}`);
}
}
asyncFun(); // Completes after 5 seconds ✅
constasyncfun=async()=>{
for(设i=0;i<5;i++){
等待一秒钟();
log(`${i}`);
}
}
asyncFun();//5秒后完成✅
您可以使用async。虽然每个都有您发布的内容,但您应该能够并行执行此异步/操作,因此我将尝试找出为什么您的所有数据都没有插入。没有理由无缘无故地减慢速度。我也不确定为什么。但我预计会有24000条记录,而且它的作用会小得多。这是ike 3000或5000当我截短表并重新运行它时,数字并不总是相同的。所以我认为我在太短的时间内抛出了太多http.get请求和/或太多MYSQL调用,导致遗漏/删除了一些内容。@Joe我想感谢你建议我重新查看我的代码,但我发现我没有在每个exports.importResponse()的末尾显式调用connection.release()。我认为connection.release()是自动调用的,但当我再次检查并显式添加它时,它现在工作了,所有24000条记录都按预期添加。再次感谢!因此循环迭代开始,传递到p。然后,循环暂停,一旦p。然后返回下一个循环迭代开始?我理解正确吗?不完全正确:循环本身不会暂停。但是然后使用传递的回调只会一个接一个地调用(设i=0;注意JavaScript不提供尾部递归,并且递归函数只能在递归深度有硬限制的情况下使用。如果你不知道这意味着什么,并且你知道你会有很多循环,那么就用承诺:)这真是一个很好的答案。我正在研究如何使for循环同步。它工作起来很有魅力:)是否需要var i=0;
?@betweenbrain哈哈,好主意。我很惊讶直到现在还没有人注意到。修复了。这可能会在较大的数据集上出现问题,因为一旦迭代完成,内存就不会被释放complete@HarshaGoli我同意,但这是一个合理的起点。如果需要大规模,递归总是在进行除非仔细优化,否则可能会出现内存问题。您应该在代码中添加一些解释,以便其他人可以从中学习。由于for循环将在异步http.get调用之前完成,因此这不会像预期的那样工作。此外,这种方式也不能保证操作顺序。如果stackoverflow有一天很慢,它可能会返回其结果位于所有其他URL之后。
const syncFun = () => {
for (let i = 0; i < 5; i++) {
oneSecond().then(() => console.log(`${i}`));
}
}
syncFun(); // Completes after 1 second ❌
const asyncFun = async () => {
for (let i = 0; i < 5; i++) {
await oneSecond();
console.log(`${i}`);
}
}
asyncFun(); // Completes after 5 seconds ✅