Promise control concurrency in 5 minutes

cause

The project needs to do an upload function, which uploads 20 videos at a time. There will be a blocking problem if it is not transmitted directly.
Because a web page can only have 6 tcp connections with the same domain name at most. If you do not control the concurrent transmission of 6 interfaces at the same time, all subsequent operations of the user calling other interfaces will be suspended. When the network is bad, it is even more disastrous. Therefore, it is necessary to control concurrency. Only 3 messages can be transmitted at a time.
There happens to be this type of interview question. Write a demo and talk about the principle.

Back end code

The back-end needs post integer basic return, random delay, random error, and can cross domains

const http = require('http')
http.createServer((req,res)=>{
    
    const delay = parseInt(Math.random()*5000)
    console.log(delay);
    setTimeout(()=>{
        const returnerror = Math.random()>0.8
        // if(returnerror){
        //     res.writeHead(500,{
        //         // 'Content-Type': 'text/plain',
        //         'Access-Control-Allow-Origin':'*',
        //         'Access-Control-Allow-Headers':'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild',
        //         'Access-Control-Allow-Methods':'GET',
        //     }).end('error,from '+req.url+' after '+delay+'ms')
        // }else{
            res.writeHead(200,{
                // 'Content-Type': 'text/plain',
                'Access-Control-Allow-Origin':'*',
                'Access-Control-Allow-Headers':'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild',
                'Access-Control-Allow-Methods':'GET',
            }).end('OK,from '+req.url+' after '+delay+'ms')
        // }
        
    },delay)   
}).listen(3000,()=>{
    console.log('Service started at 3000!');
})

Front end code

html is mainly for the display of animation, so I won't go into detail.
js is divided into two parts. One part controls dom rendering, which will not be discussed in detail. The second part is the concurrency controller
The input array contains the request address

Basic Edition

Concurrency control mainly consists of two functions and a promise queue.

  • One is responsible for adding promise to the queue through recursion.
  • The other is responsible for producing promise and processing asynchronous request logic
function handleFetchQueue(input, max) {
        const requestsQueue = []; // Request queue
        addReactive(requestsQueue) //Add a response to requestsQueue
        let i = 0;
        const req = (i)=>{  //If a promise request is generated successfully, delete the promise in the team and add another request
            return  fetch(input[i]).then(res=>res.text()).then(res=>{
                addEl(res) //Result render page list
                const index = requestsQueue.findIndex(item=>item===req)
                requestsQueue.splice(index,1)
                checkAddReq()
            })
        }
        const checkAddReq = ()=>{
            if(i>=input.length) return // The number of requests cannot exceed the limit
            if(requestsQueue.length+1 <= max) { // Concurrency cannot be out of bounds
                setTimeout(()=>{ //Add delay in order to improve the animation effect, it is not needed in practice
                    requestsQueue.push(req(i++))
                    checkAddReq()
                },50)
                
            }
        }   
       checkAddReq();
    }   
    handleFetchQueue(input,3)

Handling exceptions

The question to consider is what to do if something is abnormal.
Exceptions should be no different from concurrency control, that is, counting principle, but they need to be generated by promise. Here, you can add business logic.
We open the comments of random errors in the back-end code
Then change the front-end core logic

const req = (i)=>{  
            return  fetch(input[i]).then(async(res)=>{
                if(res.status===500){ //Here's an asynchronous change. You have to let go of catch
                    const text = await res.text()
                    throw new Error(text);
                }else{
                    return res.text()
                }
            }).then(res=>addEl(res),error=>addEl(error,true))
              .finally(()=>{ //Regardless of success or failure, the concurrency logic is the same, but the business logic in then is different
                const index = requestsQueue.findIndex(item=>item===req)
                requestsQueue.splice(index,1)
                checkAddReq()
            })
        }

summary

Full address https://github.com/fyy92/code...

  • index.html does not consider asynchrony
  • index1.html consider exceptions
  • serve.js backend code

To sum up

  • The key of concurrency control lies in two functions: one is to control the generation of business Promise, and the other is to iteratively control the addition of business Promise to the concurrency queue.
  • For exceptions, you need to ensure that the concurrency logic is the same, but the difference is the processing of business logic.

Keywords: Javascript Front-end Concurrent Programming Promise

Added by jaiswal on Mon, 24 Jan 2022 16:34:53 +0200