Javascript Nodejs:异步和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

我是node的新手,一直在学习和处理异步/承诺。现在我正在尝试创建一个进程,该进程从一个DB(例如10K行)进行插入,调用一个转换一列的webservice,然后对修改后的数据进行插入

因此,我进行了一次Oracle SQL查询,并针对结果执行了一次foreach:

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
off
res.rows
是一个执行异步工作的同步循环,通常不是一个好主意。3) 看起来您的转换在本地主机上。你能调用一个函数来完成这项工作吗?4) 获取行的逻辑和执行插入的逻辑看起来很危险。如果中间失败,会发生什么?如果这是您想要的批处理大小,为什么不一次提取1000行呢?那么您只需要确保您有办法查询下一个“未处理”集。5)
doInserts
是如何实现的?如果要插入很多行,请确保使用executeMany(),不要执行单行插入。并使用binds.Wow的可能副本,从哪里开始?:)1)
res.rows
来自哪里?2) 您的
forEach
off
res.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)
);