preface

Recently saw an interview question, of course, is the title of the passage, Ajax control concurrent requests, feel very interesting, watched under in the community, should be bytes of interview questions, also pretty much bosses about this are summarized, watched, so she also wants to try to summarize, the code below will all posted, if there is any shortage, please point out!

Serialization and parallelism of Ajax

  • Serial: The general business requirement is that the next interface needs to use the data returned by the last interface, and the common front-end request library isAxiosIs itself based onPromisetheHTTPLibrary, we directly use the chain call, or useAsync Await I’m not going to do the demo
  • Parallelism: multiple requests occurring at the same time, usually used to render the page after all the data has been retrieved, or other operations, mainly based onPromise.allThe implementation is as follows

The above simulation realized the parallel operation based on promise. all, and the printed results were entered below

Do you feel like this is over? It doesn’t exist? Now for the real thing, imagine a situation where you have to send tens of thousands of requests to a page at the same time, and then do some operations after all of them are successful. The code fails to execute and runs out of memory, which brings us back to the main topic of this article: How to control concurrent Ajax requests? I’ve asked him to output only a certain number of requests at a time until all of them are successful. I’m going to do this in two ways

Ajax’s two main solutions for concurrent request control

Based on thePromiseThe recursive implementation

The following two methods use the Tasks array in the image above, so keep that in mind. The first method, which is based on promises, looks like this: When you pass in a concurrency pool, will create the pool a workspace, returned for each workspace (request) to carry out the corresponding tasks, after a successful save, and then continue to take the task (request), until the workspace have no task, of course, failure terminated directly, general train of thought is like this, I made a comment on each line of code below, please take it

Based on theClassimplementation

The second method is based on the Class. The difference is that this method only creates a workspace. The general idea is: Create a workspace to execute tasks (requests), and push all tasks in, but only the corresponding number of concurrent tasks at a time, when less than the number of concurrent tasks, continue to take the task to execute it until there are no more tasks (requests), that’s it

The code shown

The implementation code for both methods is posted here

    const delay = function delay(interval) {
      return new Promise((res,rej) = > {
        setTimeout(() = >{ res(interval) }, interval); })}let tasks = [() = > {
      return delay(1000)},() = > {
      return delay(1003)},() = > {
      return delay(1005)},() = > {
      return delay(1002)},() = > {
      return delay(1004)},() = > {
      return delay(1006)}]// Implement parallelism with promise.all
    Promise.all(tasks.map(task= > task())).then(res= > {
      console.log(res);
    })

    // Implement based on Promise

    function creatRequest(tasks,pool) {
      // The number of requests sent per request pool
      pool = pool || 5
      // Store the results of each request (in order)
      let results = [],
      // Together is used to create workspaces. When pool is passed a number, we create workspaces accordingly
      // Create an array with the length pool and the value null
          together = new Array(pool).fill(null),
      // index is the task value obtained each time
          index = 0;
      together = together.map(() = > {
        // Manage based on promises
        return new Promise((resolve,reject) = > {
          // Create a function and execute it immediately
          const run = function run() {
            // If the task pool is empty, the request is sent successfully
            if(index >= tasks.length) {
              resolve()
              return 
            }
            // Save index to store the result of the current successful request
            let old_index = index,
            // Get the current request, and then add index, so index is stored above
            Index ++ = index++ = index++ = index++ = index++ = index++ = index++
                task = tasks[index++];
            // Execute the request
            task().then(result= > {
            // Save the successful result
              results[old_index] = result
            // Continue recursively, that is, continue to take the task to the workspace to execute
              run();
            }).catch(reason= > {
              reject(reason)
            })
          }
          // Execute immediately
          run()
        })
      })
      // Control the workspace with promise. all, i.e., two requests at a time
      return Promise.all(together).then(() = > results)
    }


    creatRequest(tasks,2).then(results= > {
      // If all are successful, all are successful
      console.log('success',results);
    }).catch(resolve= > {
      // If there is only one failure, there is a whole failure
      console.log('failure');
    })



    // Based on Class implementation
    function creatRequest(tasks,pool,callback) {
      // Parameter constraints and validation
      if(typeof pool === 'function') {
        callback = pool;
        pool = 5
      }
      if(typeofpool ! = ='number') pool = 5
      if(typeofcallback ! = ='function') callback = function () {}
      // -------
      class TaskQueue {
        // The number of runs
        runing = 0;
        // Queue all tasks that exist
        queue = [];
        // Store the result of executing the task (request)
        results = [];
        pushTask(task) {
          let self = this
          // Push the task into the workspace
          self.queue.push(task)
          // Execute the logic to send the request
          self.next()
        }
        next() {
          let self = this
          // Continue to retrieve tasks when the number of tasks in progress is smaller than the number of concurrent tasks
          while(self.runing < pool && self.queue.length) {
            self.runing++;
            // Take a task and delete a task
            let task = self.queue.shift();
            // Execute the request
            task().then(result= > {
              // Save the execution result
              self.results.push(result)
            }).finally(() = > {
              // Clear the number of running entries
              self.runing--
              // Continue with the request
              self.next()
            })
          }
          // The loop ends when there are no more tasks
          if(self.runing === 0) callback(self.results)
        }


      }
      / / instantiate
      let TQ = new TaskQueue()
      tasks.forEach(task= > TQ.pushTask(task))
    }


    creatRequest(tasks,2.results= > {
      console.log(results);
    })
Copy the code

conclusion

The above is the summary of this set of interview questions, but also make a record of their own, the follow-up will continue to update the front end of the article, and finally I hope that you front-end partners can stick to learning, technology continues to improve, come on, SAO years!!

Husband learning must be static also, only to learn also, not learn beyond wide only, not beyond into learning. Slow sex can not stimulate the essence, risk impetuous can not cure sex. Year and time chi, meaning and day go, then withered