I saw a topic about batch processing, and I felt good, but I thought I could be more detailed about the analysis process and share my analysis process here

The topic of dry

Implement a batcher function that wraps synchronous functions so that each call still returns the expected result, while ensuring that executeCount is executed 1 times

let executeCount = 0

const fn = nums= > {
  executeCount++
  return nums.map(x= > x * 2)}const batcher = f= > {
  // Todo implements batcher functions
}

const batchedFn = batcher(fn);

const main = async() = > {const [r1, r2, r3] = await Promise.all([
    batchedFn([1.2.3]),
    batchedFn([4.5]),
    batchedFn([7.8.9]]);// Satisfy the following test cases
  assert(r1).tobe([2.4.6])
  assert(r2).tobe([8.10])
  assert(r3).tobe([14.16.18])
  assert(executeCount).tobe(1)}Copy the code

Train of thought

We can divide the whole problem into two parts

  1. mainPart of the
  2. Available resources, such asexecuteCount.fn

We will provide ideas for writing batcher functions by analyzing these two

main

First let’s look at the main section of the problem code

const main = async() = > {const [r1, r2, r3] = await Promise.all([
    batchedFn([1.2.3]),
    batchedFn([4.5]),
    batchedFn([7.8.9]]);// Satisfy the following test cases
  assert(r1).tobe([2.4.6])
  assert(r2).tobe([8.10])
  assert(r3).tobe([14.16.18])
  assert(executeCount).tobe(1)}Copy the code

From the above code we can get some information:

  1. appearasync.PromiseA. asynchronous B. asynchronous C. asynchronous D. asynchronous
  2. batchedFnThe function is called three times
  3. As can be seen from the test case,batchedFnThe array_double () function doubles the data in an array

The batchedFn function is the key to main, so we will use it as a clue to analyze the resources provided by the dry code

resources

batchedFn

First we find the batchedFn function in the available resources

const batchedFn = batcher(fn);
Copy the code

BatchedFn is a function called batcher with fn as an argument. Batcher is a function called batcher

From this, we can know that the Batcher function is a function factory, and the function produced with fn as parameter is: take array as parameter, and double all the elements contained in the array passed in

When it comes to function factories, the use of closures is often a consideration

We can write the obtained information to the Batcher

const batcher = f= > {
  // Data inside the closure

  // return the function
  return arr= >{}}Copy the code

fn

So when we get batchedFn, we’re using fn as an argument, so let’s look at that

let executeCount = 0

const fn = nums= > {
  executeCount++
  return nums.map(x= > x * 2)}Copy the code

Fn doubles every single piece of data passed into the numS array and uses executeCount to count the number of times fn is used

From this we can know: batchedFn function by FN

But at the same time, in main we already know that batchedFn is called three times; According to the problem, fn can only be called once

Fn execution is not synchronized with batchedFn

Therefore, we can treat fn, or f in the Batcher, as an asynchronous operation and queue it into a microtask queue; In the process of the stack being empty, each call to batcherFn will collect the data that FN needs to process, so that when FN enters the stack, it can realize: FN will process the data collected by calling batcherFn for many times at a time

demand

At this point, we have two requirements for the batcher function:

  1. willfProcessing as an asynchronous operation
  2. Collect the incoming data for each call

Note the details of the requirement here: no matter how many times batcher’s function is called in this stack, f is called only once, and the incoming data is aggregated in one place, which the produced function itself can record, which is where closures come in

To sum up, we can deal with Batcher as follows

const batcher = f= > {
  // Used to store the data that will be obtained when the production function is called
  let nums = [];
  // Record the queued Promise to push f into the microtask queue
  let p;

  // return the function
  return arr= > {
    // Determine whether f has been queued in the microtask queue! p && p =Promise.resolve().then(_= > f(nums));

    // Record the location of incoming data so that it can be trimmed from the result
    const start = nums.length;
    // Store incoming data
    nums = nums.concat(arr);
    const end = nums.length;

    // The operation to double the data was not completed when the function was called
    // So return a Promise
    return p.then(finalNums= > {
        // return the result of each incoming data
        nums = [];
        p = undefined;
        returnfinalNums.slice(start, end); }); }}Copy the code

conclusion

A batch problem involves both async and closure, for me, just according to the answer to organize the idea is a little difficult, and this is just my own ideas, if you have better ideas or my ideas, welcome to exchange more 🙂