preface
As mentioned in the analysis of Express and Koa middleware mechanism (I), Express is a linear model, while Koa is an onion model. We have analyzed the Express middleware mechanism by analyzing connect source code before. In this article we will analyze some of Koa’s source code to help you understand its middleware mechanisms.
Koa1 is based on the CO library, so KOA1 uses generators instead of callbacks, whereas KOa2 uses async/await due to node’s async/await support
At present, we commonly used are basically KOA2, here we first for the implementation of KOA2 analysis, Koa1 first leave a pit, and then add.
Koa1 middleware
To be continued…
Koa2 middleware
The implementation of the Koa2 middleware relies on its own KOA-compose, and let’s look at the implementation of the compose function.
function compose (middleware) {
// To determine whether the middleware argument is valid, middleware requires an array with each array element being 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
// Recursively returns a function that returns a Promise object
return dispatch(0)
function dispatch (i) {
// when the next method is called multiple times
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
// Last piece of middleware
if (i === middleware.length) fn = next
if(! fn)return Promise.resolve()
// Promise encapsulates middleware to make recursive calls
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
Copy the code
The use function in Koa pushes middleware, and the middleware array passed in the compose function is the middleware array. A recursive call to that array in compose returns a chain of promises.
The following is an example of how middleware performs this process:
// Middleware Fn1 and Fn2
async function fn1 (ctx, next) {
console.log('first: start')
await next()
console.log('first: end')}async function fn2 (ctx, next) {
console.log('second: start')
await next()
console.log('second: end')}// Simulate middleware array
const arr = [fn1, fn2]
// Execute the function, which returns a Promise object
compose(arr)()
// The result after execution
// first: start
// second: start
// second: end
// first: end
Copy the code
The next function is essentially the next middleware, and await await the internal Promise, so its execution results in an onion peeling pattern.
function mycompose() {
return function () {
const ctx = {}
return Promise.resolve(fn1(ctx, () => {
return Promise.resolve(fn2(ctx, () => {
}))
}))
}
}
mycompose()()
Copy the code
conclusion
Koa is much lighter than Express, and it is just a basic structure. When you need other functions, you can use the corresponding middleware. Koa-compose is one of them, and its routing and other functions are implemented in other middleware. Even koa-Compose’s overall code is still pretty neat.