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.