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

How to implement mask layer in HTML How to use mask layer in HTML

Using mask layers in web pages can prevent repeat...

MySQL sorting Chinese details and examples

Detailed explanation of MySQL sorting Chinese cha...

How to use CSS attribute selectors to splice HTML DNA

CSS attribute selectors are amazing. They can hel...

JavaScript to implement checkbox selection or cancellation

This article shares the specific code of JavaScri...

Detailed explanation of MySQL sql_mode query and setting

1. Execute SQL to view select @@session.sql_mode;...

MySQL transaction, isolation level and lock usage example analysis

This article uses examples to describe MySQL tran...

PHP-HTMLhtml important knowledge points notes (must read)

1. Use frameset, frame and iframe to realize mult...

js array fill() filling method

Table of contents 1. fill() syntax 2. Use of fill...

A complete guide to the Docker command line (18 things you have to know)

Preface A Docker image consists of a Dockerfile a...

How to install Android x86 in vmware virtual machine

Sometimes you just want to test an app but don’t ...

Detailed explanation of Nginx proxy_redirect usage

Today, I encountered a little problem when I was ...

MySQL 8.0.20 installation and configuration tutorial under Win10

MySQL 8.0.20 installation and configuration super...