Javascript Nodejs:异步和forEach问题-需要等待异步解决
我是node的新手,一直在学习和处理异步/承诺。现在我正在尝试创建一个进程,该进程从一个DB(例如10K行)进行插入,调用一个转换一列的webservice,然后对修改后的数据进行插入 因此,我进行了一次Oracle SQL查询,并针对结果执行了一次foreach:Javascript Nodejs:异步和forEach问题-需要等待异步解决,javascript,node.js,Javascript,Node.js,我是node的新手,一直在学习和处理异步/承诺。现在我正在尝试创建一个进程,该进程从一个DB(例如10K行)进行插入,调用一个转换一列的webservice,然后对修改后的数据进行插入 因此,我进行了一次Oracle SQL查询,并针对结果执行了一次foreach: let counter = 0; var binds = []; res.rows.forEach((row) => { var original_data = row[0]; Transform(ori
let counter = 0;
var binds = [];
res.rows.forEach((row) => {
var original_data = row[0];
Transform(original_data).then(new_data => {
counter++;
binds.push([original_data,new_data]);
if (counter % 1000 === 0){
console.log(`1K rows`);
doInserts(binds);
binds = [];
}
});
});
我每1000行调用doInserts
,因此在Oracle上打开的事务不多
Transform函数调用一个webservice,它使用我需要的值进行解析
function Transform(value){
return new Promise(function(resolve, reject){
var requestPath = `http://localhost:3000/transform/${value}`;
var req = request.get(requestPath, function(err, response, body){
if (!err && response.statusCode == 200){
resolve(body);
}else{
reject("API didn't respond.");
}
}).end();
});
}
然而,当foreach有10K行时,这会阻塞webservice(我使用库来连接)。我在想,foreach并不是同步地一次转换一个
这可能是因为我不知道很多节点、异步和承诺。。但我很困惑。有人可以帮忙吗?您可以使用任何promise库或ES6 promise来收集一系列承诺并一起解决它们 在本例中,我将使用
请注意,
Promise.all
将同时尝试解析数组中的所有承诺。如果数据库有连接计数限制,则某些呼叫可能会失败 您可以使用任何promise库或ES6 promise来收集一系列承诺并一起解决它们
在本例中,我将使用
请注意,
Promise.all
将同时尝试解析数组中的所有承诺。如果数据库有连接计数限制,则某些呼叫可能会失败 你同时在做很多事情。尝试设置一个并发。您可以使用bluebird's Promise.map:
你同时也在做许多要求。尝试设置一个并发。您可以使用bluebird's Promise.map:
如果一个答案失败,并且所有成功的答案都丢失,则所选答案将被拒绝(如果最后一个答案被拒绝,则除了最后一个结果之外,您已经丢失了所有答案) 这是适合您的情况的代码。有关该代码的更多信息可以找到,它不使用bluebird,而是使用lib.throttle(来自包含我编写的常用函数的lib)
如果一个答案失败,并且所有成功的答案都丢失,则所选答案将被拒绝(如果最后一个答案被拒绝,则除了最后一个结果之外,您已经丢失了所有答案) 这是适合您的情况的代码。有关该代码的更多信息可以找到,它不使用bluebird,而是使用lib.throttle(来自包含我编写的常用函数的lib)
Wow的可能副本,从哪里开始?:)1)
res.rows
来自哪里?2) 您的forEach
offres.rows
是一个执行异步工作的同步循环,通常不是一个好主意。3) 看起来您的转换在本地主机上。你能调用一个函数来完成这项工作吗?4) 获取行的逻辑和执行插入的逻辑看起来很危险。如果中间失败,会发生什么?如果这是您想要的批处理大小,为什么不一次提取1000行呢?那么您只需要确保您有办法查询下一个“未处理”集。5) doInserts
是如何实现的?如果要插入很多行,请确保使用executeMany(),不要执行单行插入。并使用binds.Wow的可能副本,从哪里开始?:)1) res.rows
来自哪里?2) 您的forEach
offres.rows
是一个执行异步工作的同步循环,通常不是一个好主意。3) 看起来您的转换在本地主机上。你能调用一个函数来完成这项工作吗?4) 获取行的逻辑和执行插入的逻辑看起来很危险。如果中间失败,会发生什么?如果这是您想要的批处理大小,为什么不一次提取1000行呢?那么您只需要确保您有办法查询下一个“未处理”集。5) doInserts
是如何实现的?如果要插入很多行,请确保使用executeMany(),不要执行单行插入。使用绑定。谢谢Jason,但我认为这就是正在发生的事情。Transform()中的请求建立了太多连接,导致API停止响应。谢谢Jason,但我认为这就是发生的情况。Transform()中的请求建立的连接太多,导致API停止响应。
const Promise = require('bluebird');
async function resolvingManyPromises() {
let counter = 0;
let binds = [];
let promiseArray = [];
res.rows.forEach(row => {
var original_data = row[0];
promiseArray.push(Transform(original_data));
});
const resolvedPromises = await Promise.all(promiseArray);
// Do something with the resolved values resolvedPromises
}
await Promise.map(rows, async (row) => {
const new_data = await Transform(row[0])
...
}, {concurrency: 3}) // allow max 3 request at the same time
//lib comes from: https://github.com/amsterdamharu/lib/blob/master/src/index.js
const lib = require("lib");
const Fail = function(reason){this.reason=reason;};
const isFail = o=>(o&&o.constructor)===Fail;
const isNotFail = o=>!isFail(o);
const handleBatch = results =>{//this will handle results of a batch
//failed are the requests that failed
//you may want to save the ones that failed to file or something
const failed = results.filter(isFail);
const successes = results.filter(result=>!isFail(result));
return doInserts(successes);
};
const processor = throttler => row =>
throttler(//throttling Transform to max 10 active
row=>
Transform(row[0])
.then(new_data =>[row[0],new_data])
)(row)
.catch(err=>new Fail([err,row]))//catch reject and resolve with fail object
;
//start the process
lib.batchProcess (handleBatch) (1000) (processor(lib.throttle(10))) ([]) (res.rows)
.then(
results=>console.log("Process done")
,err=>console.error("This should not happen:".err)
);