Javascript 如何使用vanilla Node.js并行运行500个请求,20个

Javascript 如何使用vanilla Node.js并行运行500个请求,20个,javascript,node.js,es6-promise,Javascript,Node.js,Es6 Promise,我有一个vanilla Node.js代码: const http = require('http'); const host = 'example.com'; const path = '/'; let i = 0; const run = () => { console.log(i++); return new Promise(resolve => { const req = http.request({host, path}, res => {

我有一个vanilla Node.js代码:

const http = require('http');

const host = 'example.com';
const path = '/';

let i = 0;

const run = () => {

  console.log(i++);

  return new Promise(resolve => {

    const req = http.request({host, path}, res => {
      res.pipe(process.stdout);
      res.once('end', resolve);
    });

    req.end();

  });

};

async function doall() {
  for (let i = 0; i < 50; i++) {
    await Promise.all(new Array(10).fill(null).map(run));
  }
}

const now = Date.now();

console.log('Starting up.');

doall().then(_ => {
  console.log('done after:', Date.now() - now, 'millis');
});

// the end
consthttp=require('http');
const host='example.com';
常量路径='/';
设i=0;
常量运行=()=>{
console.log(i++);
返回新承诺(解决=>{
const req=http.request({host,path},res=>{
物料管道(工艺标准);
决议一次(“结束”,决议);
});
请求结束();
});
};
异步函数doall(){
for(设i=0;i<50;i++){
等待承诺.all(新数组(10).fill(null).map(run));
}
}
const now=Date.now();
console.log(“启动”);
doall()。然后(=>{
log('done after:',Date.now()-now,'millis');
});
//结局
这工作-它运行50套10。。。但问题是,所有10个都完成了,然后下一个10个开始,然后下一个10个完成。因此,在每个集合之间,都有0个请求正在进行的时刻

是否有办法使用vanilla Node.js并承诺复制
async.eachLimit(新数组(500),20,…)

这似乎有效:

const http = require('http');

const host = 'example.com';
const path = '/';

let i = 0;

const makeRequest = () => {

  console.log(i++);

  return new Promise(resolve => {

    const req = http.request({host, path}, res => {
      res.pipe(process.stdout);
      res.once('end', resolve);
    });

    req.end();

  });

};

const run = (v) => {

  v.count++;
  v.total++;

  if (v.total > v.max) {
    return;
  }

  return makeRequest().then(_ => {

    v.count--;

    if (v.count < v.concurrency) {
      return run(v);
    }

  });
};

async function doall() {

  const v = {
    count: 0,
    total: 0,
    max: 500,
    concurrency: 20
  };

  const initialSet = new Array(v.concurrency).fill(null);

  return Promise.all(initialSet.map(_ => run(v)));

}

const now = Date.now();

console.log('Starting up.');

doall().then(_ => {
  console.log('done after:', Date.now() - now, 'millis');
});
consthttp=require('http');
const host='example.com';
常量路径='/';
设i=0;
const makeRequest=()=>{
console.log(i++);
返回新承诺(解决=>{
const req=http.request({host,path},res=>{
物料管道(工艺标准);
决议一次(“结束”,决议);
});
请求结束();
});
};
常量运行=(v)=>{
v、 计数++;
v、 总计++;
如果(v.total>v.max){
返回;
}
返回makeRequest(){
v、 计数--;
if(v.countrun(v));
}
const now=Date.now();
console.log(“启动”);
doall()。然后(=>{
log('done after:',Date.now()-now,'millis');
});

现在任何时候都有20个并行运行,总共有500个。所以现在它的行为更像是
async.eachLimit(新数组(500)…,20,…)
这是我提出的解决方案:

函数运行(){
//出于代码段的目的,使用随机超时模拟这一点。
返回新承诺((resolve)=>setTimeout(resolve,Math.random()*300))
}
函数doAll(totalCount,maxConcurrent){
返回新承诺((解决)=>{
让开始=0;
设=0;
//每次我们开始一项任务,我们都会这样做
常量队列=()=>{
启动++;
console.log('starting',started)
//我假设您希望将错误计算为已完成,然后继续下一步
run()。然后(onsetled,onsetled);
}
//每次完成任务时,我们都会这样做:
const onsetled=()=>{
已解决++;
console.log('finished',结算)
如果(开始<总计数){
排队();
}
如果(已结算===totalCount){
解决();
}
};
//开始第一批。
while(启动。然后(()=>console.log('all done')
那么您想在单个请求每次失败/成功后排队等待下一个请求吗?是的,如果当前进行中的请求少于20个,那么这是正确的。这个问题的解决方案是:@jfriend00我试图弄清楚这个问题是如何使用vanilla JS来完成的,因此,我们不必导入依赖项等。您的问题被标记为contains代码的副本(
mapConcurrent()
函数),您可以复制并使用它。我还为您提供了三个其他实现的链接,您也可以复制和使用它们。其他答案中已有大量来源。我给了你四个不依赖外部库的选项。但是你正在重新运行相同的
v
,现在不是吗?我不会在任何地方返回
v
,你是什么意思?不,不返回,但是你
运行(v)
其中
v
是父函数的参数;假设你用这个来获取繁殖列表,你能用你的代码和参数为所有的品种画一张图片吗?@Icepickle
v
与请求无关。它只跟踪有多少连接正在运行,还有多少连接仍在等待运行。您似乎在抱怨的是
path
变量,它是一个常量。但是,通过将其制作为一个数组并从中弹出到每个新的request@Icepickle但是他在每次函数调用中都创建了一个新对象,所以重用没有问题。代码是完全可重入的。如果
v
是全局的,这将是一个问题,但由于它是作为输入传入的,每个调用都有自己的状态变量。它看起来没有任何方法可以传回错误或按顺序累积结果。
它看起来没有任何方法可以传回错误或按顺序累积结果。
正确,事实并非如此。如果这些都是需要的,那么这可能是不够的<代码>我也不知道它是如何开始递减的它没有;这个数字总是在增加。当通过代码
if(started
if(started