Learning summary, in order to build wheels to measure the learning effect. The output of this paper is planned after seeing the shadow of Reduce in both Koa-compose and Redux
Reduce implementation
The reduce() method performs a reducer function (in ascending order) that you provide on each element in the array, summarizing its results into a single return value.
The reducer function receives four parameters:
- Accumulator (ACC)
- Current Value (CUR)
- Current Index (IDX)
- Source Array (SRC)
The return value from the Reducer function is assigned to the accumulator and is remembered in each iteration of the array and becomes the final single result value.
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
Copy the code
Implement a Reduce
Array.prototype.reduce1 = function (callback, initValue) {
// The array to call
let curArr = this
// Last return value
let returnValue
/ / starting point
let startIndex
// Empty array - with an initial value
if(curArr.length === 0) {
return initValue
}
// Check whether the second argument is passed (initial value)
returnValue = typeof initValue === 'undefined' ? curArr[0] : initValue
// The initial iteration position
startIndex = typeof initValue === 'undefined' ? 1 : 0
for (let index = startIndex; index < curArr.length; index++) {
// Execute callback in turn
returnValue = callback(returnValue, curArr[index], index, curArr)
}
return returnValue
}
console.log('reduce'[1.2.3].reduce1((pre, cur) = > pre + cur, 1))
/ / 7
Copy the code
Reduce implements the sequential execution of promises
Thinking of sequential execution of promises is, of course, possible with async await. This paper mainly talks about the realization of Reduce.
The runQueuePromise method will be called by an array that returns a Promise for each item, and each Promise in the array will be executed in turn
const f1 = () = > new Promise((resolve, reject) = > {
setTimeout(() = > {
console.log('f1 running')
resolve(1)})})const f2 = () = > new Promise((resolve, reject) = > {
setTimeout(() = > {
console.log('f2 running')
resolve(1)})})const fnArray = [f1, f2]
function runQueuePromise(arr, initValue) {
return arr.reduce((preChain, curFunction) = > preChain.then(curFunction), Promise.resolve(initValue))
}
runQueuePromise(fnArray, 'initvalue')
Copy the code
Reduce implementation pipe
Pipe is about piecing together small features to create our own desired features.
Ex. :
const fn1 = x= > x + 1
const fn2 = x= > x + 2
Copy the code
We want to pass a parameter through the first function and then through the second function. The most direct and simplest way is:
f2(f1(1)) / / 4
Copy the code
Write a simple pipe function that returns a new function for the purpose above
Pipe (f1, f2, f3) is a curried function that returns a new function that completes (… args) => f3(f2(f1(… Args))).
const fn1 = x= > x + 1
const fn2 = x= > x + 2
const pipe = (. funcs) = > input= > funcs.reduce(
(f1, f2) = > f2(f1),
input
)
const newPipe = pipe(fn1, fn2)
console.log('pipe:', newPipe(1))
Copy the code
Reduce implementation compose
Compose, like pipe, performs a series of tasks (methods), such as:
let funcs = [fn1, fn2, fn3, fn4]
letcomposeFunc = compose(... funcs) composeFunc(args) fn1(fn2(fn3(fn4(args))))// compose
fn1(fn2(fn3(fn4(args))))
// pipe
fn4(fn3(fn2(fn1(args))))
Copy the code
The only difference is the order of execution
1. Process-oriented implementation: recursion
Closure is used to store result and function array length as well as traversal index using closure variable, and use recursive thought to carry out cumulative calculation of results.
function compose(. args) {
// Function array length. The closure variable functions the array length and traversal index
let len = args.length
// Number of functions to be executed: total - 1
let total = len - 1
// The closure variable stores the result
let result
return function fn(. args1) {
// Execute the function from right to left
result = args[total].apply(this, args1)
// The array of functions is complete
if (total <= 0) {
total = len - 1
return total
}
total--
return fn.call(null, result)
}
}
Copy the code
2. Implementation of redux version
Take full advantage of the reduce method, my favorite
/ / version of the story
function compose(. funcs) {
if (funcs.length === 0) {
return arg= > arg
}
if (funcs.length === 1) {
return funcs[0]}return funcs.reduce((a, b) = > (. args) = >a(b(... args))) }Copy the code
3. Implementation of koa-compose version
function compose (middleware) {
if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array! ')
for (const fn of middleware) {
if (typeoffn ! = ='function') throw new TypeError('Middleware must be composed of functions! ')}/ * * *@param {Object} context
* @return {Promise}
* @api public* /
return function (context, next) {
// last called middleware #
let index = -1
return dispatch(0)
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if(! fn)return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
Copy the code
So far, reduce has many uses.
PS: Welcome to exchange and study, please point out any shortcomings.