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

A brief discussion on using virtual lists to optimize tables in el-table

Table of contents Preface Solution Specific imple...

Introduction and tips for using the interactive visualization JS library gojs

Table of contents 1. Introduction to gojs 2. Gojs...

Do you know the meaning of special symbols in URL?

1.# # represents a location in a web page. The ch...

Use vue2+elementui for hover prompts

Vue2+elementui's hover prompts are divided in...

A question about border-radius value setting

Problem Record Today I was going to complete a sm...

A brief discussion on the $notify points of element

My original intention was to encapsulate the $not...

JavaScript canvas realizes the effect of nine-square grid cutting

This article shares the specific code of canvas t...

10 Best Practices for Building and Maintaining Large-Scale Vue.js Projects

Table of contents 1. Use slots to make components...

Solution to forgetting the MYSQL database password under MAC

Quick solution for forgetting MYSQL database pass...

CSS3 text animation effects

Effect html <div class="sp-container"...

VMware Workstation installation Linux system

From getting started to becoming a novice, the Li...

Use vue3 to implement a human-cat communication applet

Table of contents Preface Initialize the project ...