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
main
Part of the- Available resources, such as
executeCount
.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:
- appear
async
.Promise
A. asynchronous B. asynchronous C. asynchronous D. asynchronous batchedFn
The function is called three times- As can be seen from the test case,
batchedFn
The 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:
- will
f
Processing as an asynchronous operation - 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 🙂