Example code for implementing concurrent request control in JavaScript/TypeScript

Example code for implementing concurrent request control in JavaScript/TypeScript

Scenario

Suppose there are 10 requests, but the maximum number of concurrent requests is 5, and the request results are required. This is a simple concurrent request control.

simulation

Use setTimeout to perform a simple simulation of a request

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);

By simulating the request in this way, the essence is Promise

When there is no concurrency control

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

You can see that the output is 5 2 3 4 1, which is output according to the timeout time.

Concurrency conditions

Assuming the maximum number of concurrent connections is 2, create a class

class Concurrent {
 private maxConcurrent: number = 2;

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

The first concurrency control

Think about it, split the Promise array according to the maximum number of concurrency. If a Promise is fulfilled, remove it, and then add the pending Promise. Promise.race can help us meet this requirement

class Concurrent {
 private maxConcurrent: number = 2;

 constructor(count: number = 2) {
 this.maxConcurrent = count;
 }
 public async useRace(fns: Function[]) {
 const running: any[] = [];
 // Add Promises according to the number of concurrency // Promises will call back an index so that we can know which Promise has resolved 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>(running);
  const nextFn = fns.shift()!;
  // Remove the completed Promise and put the new one in runing.splice(idx, 1, nextFn(idx));
  handle();
  } else {
  // If the array has been cleared, it means there is no Promise to be executed, you can change it to Promise.all
  await Promise.all(running);
  }
 };
 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

You can see that the output has changed. Why is this happening? Let's analyze it. The maximum number of concurrent connections is 2.

// The first thing to execute is 1 2
1 It takes 1000 MS to complete
2 300 MS required

2 is executed, the timeline becomes 300. Remove 2. Add 3. Start executing 3.
3 takes 400ms. The execution time becomes 700ms. Remove 3. Add 4. Start executing 4.
4 Requires 500MS
The timeline reaches 1000MS, 1 is executed and removed, 5 is added, and 5 is started
The timeline reaches 1200MS, and steps 4 and 5 are executed at the same time.

Second option

You can use the await mechanism, which is actually a little trick

The await expression will pause the execution of the current async function and wait for the Promise to complete. If the Promise is fulfilled, the resolve function parameter of the callback is used as the value of the await expression to continue executing the async function.

If the current number of concurrent requests exceeds the maximum number of concurrent requests, you can set a new Promise and await. When waiting for other requests to complete, resolve and remove the wait. Therefore, you need to add two new states, the current number of concurrent requests and an array to store the resolve callback function.

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 the maximum number of concurrent connections has exceeded the maximum if (this.currentCount > this.maxConcurrent) {
  // wait is a Promise, which becomes fulfilled as long as resolve is called const wait = new Promise((resolve) => {
  this.list.push(resolve);
  });
  // When resolve is not called, await wait will be blocked here;
 }
 //Execute function await fn();
 this.currentCount -= 1;
 if (this.list.length) {
  // Take out resolve and call it, so that wait is completed and you can execute it below 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

Summarize

Both methods can achieve concurrency control, but the implementation methods are different. They are mainly implemented by Promise. In addition, the implementation method does not consider abnormal situations, which can be added by yourself.

This concludes this article about sample code for implementing concurrent request control with JavaScript/TypeScript. For more content about JavaScript concurrent request control, please search previous articles on 123WORDPRESS.COM or continue browsing the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed explanation of JavaScript private class fields and TypeScript private modifiers
  • JS Decorator Pattern and TypeScript Decorators
  • Detailed explanation of the simple use of RxJS in TypeScript
  • How to use TypeScript in Vue.js
  • Specific use of void in JavaScript and TypeScript
  • Typescript nodejs dependency injection implementation code detailed explanation
  • vue + typescript + video.js to realize streaming video monitoring function
  • Teach you how to use TypeScript to develop Node.js applications
  • The connection between JavaScript and TypeScript

<<:  js addition, subtraction, multiplication and division precise calculation method example code

>>:  MySQL 5.7.17 winx64 installation and configuration method graphic tutorial

Recommend

mysql security management details

Table of contents 1. Introduce according to the o...

Docker installation of Nginx problems and error analysis

question: The following error occurred when insta...

Solution to the MySQL error "Every derived table must have its own alias"

MySQL reports an error when executing multi-table...

javascript implements web version of pinball game

The web pinball game implemented using javeScript...

Control the vertical center of the text in the HTML text box through CSS

When the height attribute of Text is defined, the ...

In-depth analysis of the Linux kernel macro container_of

1. As mentioned above I saw this macro when I was...

How to change mysql password under Centos

1. Modify MySQL login settings: # vim /etc/my.cnf...

How to use the Linux md5sum command

01. Command Overview md5sum - Calculate and verif...

Detailed explanation of CSS sticky positioning position: sticky problem pit

Preface: position:sticky is a new attribute of CS...

jQuery realizes the effect of theater seat selection and reservation

jQuery realizes the effect of theater seat select...

Convert psd cut image to div+css format

PSD to div css web page cutting example Step 1: F...