Familiar with koa-compose middleware source code
Goethe once said: reading a good book, is talking with noble people. The same can be said: read the source code, but also a way to learn and communicate with the author.
reference
Juejin. Cn/post / 700537…
koa-compose
Middleware refers to independent plug-ins that link the entire Koa application and share resources, “link” for “next” and “shared resources for context”.
There is a typical middleware GIF in the KOA documentation
compose
The middleware process is handled primarily with the compose function
Compose executes the logic:
- Accepts an argument, the checksum argument is an array, and each entry in the checksum array is a function.
- Returns a function that takes two arguments, respectively
context
andnext
, this function finally returnsPromise
.
/**
* Compose `middleware` returning
* a fully valid middleware comprised
* of all those which are passed.
*
* @param {Array} middleware
* @return {Function}
* @api public* /
function compose (middleware) {
// Check that each item in the array is a function
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){
// omit, as described below}}}Copy the code
dispatch
function dispatch (i) {
Fn1, fn2, fn3...
let fn = middleware[i]
Compose (stack)({}) executes the first fn in the middleware array, next(), dispatch.bind(null, I + 1), next FN in the middleware array, etc
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))}Copy the code
- complete
# 3 Details1.The next function is called multiple times in fn, where the index closure holds the count2.Last fn has no next, returnsPromise.resolve()
3.Error capture is wrapped by the previous FNfunction dispatch (i) {
// Multiple calls to a function fail
// await next() where index is closure data and will be updated every time the dispatch is dropped. If fn executes next twice, the update will clash
// await next()
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
Fn1, fn2, fn3...
let fn = middleware[i]
// next = undefined
if (i === middleware.length) fn = next
// Return promise.resolve ()
if(! fn)return Promise.resolve()
// When an error occurs, the next function of the last fn is not executed. The catch function of the last fn is executed
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))}catch (err) {
return Promise.reject(err)
}
}
Copy the code
reporter
1. In the bind function, if this is not required, it is written as null
2. Closures can be used to count and check repeated execution
Function compose(){let index = -1 dispatch(0) dispatch(I){// dispatch(0) 0 "0" 1 "0" 1 "1" error if(i<=index) throw .. index = i return fn(dispatch(i+1)) } } fn(next){ next() next() }Copy the code
3. Sichuan elder brother yyds