JavaScript/TypeScript 동시 요청 제어를 위한 예제 코드

장면


가령 10개의 요청이 있지만 가장 큰 병발 수량은 5개이며 요청 결과를 받아야 한다고 가정하면 간단한 병발 요청 제어이다

시뮬레이션


set Timeout을 이용해서 간단한 모방 요청을 실행합니다.

let startTime = Date.now();
const timeout = (timeout: number, ret: number) => {
 return (idx?: any) =>
 new Promise((resolve) => {
  setTimeout(() => {
  const compare = Date.now() - startTime;
  console.log(`At ${Math.floor(compare / 100)}00 return`, ret);
  resolve(idx);
  }, timeout);
 });
};

const timeout1 = timeout(1000, 1);
const timeout2 = timeout(300, 2);
const timeout3 = timeout(400, 3);
const timeout4 = timeout(500, 4);
const timeout5 = timeout(200, 5);

이렇게 요청을 시뮬레이션하면 본질은 Promise

병발 제어가 없을 때.


const run = async () => {
 startTime = Date.now();
 await Promise.all([
 timeout1(),
 timeout2(),
 timeout3(),
 timeout4(),
 timeout5(),
 ]);
};

run();

At 200 return 5
At 300 return 2
At 400 return 3
At 500 return 4
At 1000 return 1

출력이 52 3 4 1입니다. 타임아웃으로 출력이 됩니다.

병발 조건


같은 시간의 최대 병렬 수가 2이라고 가정하고 클래스를 만듭니다

class Concurrent {
 private maxConcurrent: number = 2;

 constructor(count: number = 2) {
 this.maxConcurrent = count;
 }
}


첫 번째 병렬 제어


생각해 보세요. 최대 병발수에 따라 Promise 그룹을 나누고, Promise가fulfilled될 때 제거하고pending 상태의 Promise를 추가합니다.Promise.레이스가 이 수요를 충족시킬 수 있어요.

class Concurrent {
 private maxConcurrent: number = 2;

 constructor(count: number = 2) {
 this.maxConcurrent = count;
 }
 public async useRace(fns: Function[]) {
 const runing: any[] = [];
 //  ,  Promise  
 // Promise  ,  Promise   resolve  
 for (let i = 0; i < this.maxConcurrent; i++) {
  if (fns.length) {
  const fn = fns.shift()!;
  runing.push(fn(i));
  }
 }
 const handle = async () => {
  if (fns.length) {
  const idx = await Promise.race<number>(runing);
  const nextFn = fns.shift()!;
  //   Promise, 
  runing.splice(idx, 1, nextFn(idx));
  handle();
  } else {
  //  ,  Promise  ,  Promise.all
  await Promise.all(runing);
  }
 };
 handle();
 }
}

const run = async () => {
 const concurrent = new Concurrent();
 startTime = Date.now();
 await concurrent.useRace([timeout1, timeout2, timeout3, timeout4, timeout5]);
};

At 300 return 2
At 700 return 3
At 1000 return 1
At 1200 return 5
At 1200 return 4

출력이 바뀌었음을 볼 수 있다. 왜 이러는지 분석해 보자. 최대 병발수 2
//우선 1 2
1 1000MS가 필요합니다.
2 300MS 필요
2 실행 완료, 타임라인 300 제거 2 가입 3 실행 시작 3
3 400MS 실행 후 700 제거 3 가입 4 시작 4
4 500MS 필요
타임라인이 1000MS에 와서 1 실행 완료 제거 1 가입 5 실행 시작 5
타임라인이 1200MS에 이르러 4와 5가 동시에 실행되었다

두 번째 방안


await의 메커니즘을 이용할 수 있는 것도 사실 작은 기교이다
await 표현식은 현재 asyncfunction의 실행을 멈추고 Promise 처리가 끝날 때까지 기다립니다.Promise가 정상적으로 처리되면 리셋된resolve 함수 인자는await 표현식의 값으로 asyncfunction를 계속 실행합니다.
현재 병렬 수가 최대 병렬 수를 초과하면 새로운 Promise를 설정하고await, 다른 요청이 완료될 때,resolve, 제거 대기를 설정할 수 있습니다. 따라서 두 개의 상태를 추가해야 합니다. 현재 병렬 수, 그리고resolve라는 리셋 함수를 저장하는 수조

class Concurrent {
 private maxConcurrent: number = 2;
 private list: Function[] = [];
 private currentCount: number = 0;

 constructor(count: number = 2) {
 this.maxConcurrent = count;
 }
 public async add(fn: Function) {
 this.currentCount += 1;
 //  
 if (this.currentCount > this.maxConcurrent) {
  // wait   Promise,  resolve   fulfilled  
  const wait = new Promise((resolve) => {
  this.list.push(resolve);
  });
  //   resolve  , 
  await wait;
 }
 //  
 await fn();
 this.currentCount -= 1;
 if (this.list.length) {
  //   resolve  , ,  wait  , 
  const resolveHandler = this.list.shift()!;
  resolveHandler();
 }
 }
}

const run = async () => {
 const concurrent = new Concurrent();
 startTime = Date.now();
 concurrent.add(timeout1);
 concurrent.add(timeout2);
 concurrent.add(timeout3);
 concurrent.add(timeout4);
 concurrent.add(timeout5);
};

run();

At 300 return 2
At 700 return 3
At 1000 return 1
At 1200 return 5
At 1200 return 4


총결산


이 두 가지 방식은 모두 병행 제어를 실현할 수 있지만 실현 방식은 그다지 같지 않다. 주로 Promise에 의해 실현된다. 또한 실현 방식에서 이상한 상황을 고려하지 않는다. 이것은 스스로 덧붙일 수 있다.
JavaScript/TypeScript 병발 요청 제어의 예시 코드에 관한 이 글은 여기에 소개되었습니다. 더 많은 JavaScript 병발 요청 제어 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 저희 글을 많이 사랑해 주십시오!

좋은 웹페이지 즐겨찾기