In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "how to better understand middleware and onion model". In daily operation, I believe that many people have doubts about how to better understand middleware and onion model. I have consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the questions of "how to better understand middleware and onion model"! Next, please follow the editor to study!
1. Koa middleware
We found the definition of the middleware type in the index.d.ts header file under the @ types/koa-compose package:
/ / @ types/koa-compose/index.d.ts declare namespace compose {type Middleware = (context: t, next: Koa.Next) = > any; type ComposedMiddleware = (context: t, next?: Koa.Next) = > Promise;} / / @ types/koa/index.d.ts = > Koa.Next type Next = () = > Promise
By looking at the definition of the Middleware type, we can see that in Koa, middleware is a normal function that takes two parameters: context and next. Where context represents the context object and next represents a function object that returns the Promise object when called.
After understanding what the Koa middleware is, let's introduce the core of the Koa middleware, namely the compose function:
Function wait (ms) {return new Promise ((resolve) = > setTimeout (resolve, ms | | 1));} const arr = []; const stack = []; / / type Middleware = (context: t, next: Koa.Next) = > any; stack.push (async (context, next) = > {arr.push (1); await wait (1); await next (); await wait (1); arr.push (6);}) Stack.push (async (context, next) = > {arr.push (2); await wait (1); await next (); await wait (1); arr.push (5);}); stack.push (async (context, next) = > {arr.push (3); await wait (1); await next (); await wait (1); arr.push (4);}); await compose (stack) ({})
For the above code, we want the value of the array arr to be [1, 2, 3, 4, 5, 6] after executing the compose (stack) ({}) statement. Let's not care about how the compose function is implemented here. Let's analyze the execution flow of the above three middleware if we want to find the desired results of the array arr output:
1. Start execution of the first middleware, press 1 into the arr array, where the value of the arr array is [1], and then wait 1 millisecond. To ensure that item 1 of the arr array is 2, we need to start executing the second middleware after calling the next function.
two。 Start execution of the second middleware, press 2 into the arr array, where the value of the arr array is [1,2], and continue to wait 1 millisecond. To ensure that item 2 of the arr array is 3, we also need to start executing the third middleware after calling the next function.
3. Start execution of the third middleware, press 3 into the arr array, where the value of the arr array is [1, 2, 3], and wait 1 millisecond. To ensure that item 3 of the arr array is 4, we need to be able to proceed after calling the third intermediate next function.
4. When the third middleware is completed, the value of the arr array is [1,2,3,4]. So in order to ensure that item 4 of the arr array is 5, we need to execute the statement after returning the second middleware next function after the third middleware execution is complete.
5. When the second middleware is completed, the value of the arr array is [1, 2, 3, 4, 5]. Similarly, in order to ensure that item 5 of the arr array is 6, we need to execute the statement after returning the first middleware next function after the second middleware execution is complete.
6. When the first middleware is completed, the value of the arr array is [1, 2, 3, 4, 5, 6].
In order to understand the above execution flow more intuitively, we can regard each middleware as a big task, and then take the next function as the demarcation point, and then decompose each large task into three small tasks: beforeNext, next and afterNext.
In the figure above, we start with the beforeNext task of middleware one, and then follow the execution steps of the purple arrow to complete the task scheduling of the middleware. In this article, what is worth learning from the 77.9k Axios project, Brother Po analyzes the implementation of Axios interceptor from three aspects: task registration, task scheduling and task scheduling. Similarly, Brother Po will analyze the mechanism of Koa middleware from the above three aspects.
1.1 Task Registration
In Koa, after we create a Koa application object, we can register the middleware by calling the object's use method:
Const Koa = require ('koa'); const app = new Koa (); app.use (async (ctx, next) = > {const start = Date.now (); await next (); const ms = Date.now ()-start; console.log (`${ctx.method} ${ctx.url}-${ms} ms`);})
In fact, the implementation of the use method is very simple, in the lib/application.js file, we found its definition:
/ / lib/application.js module.exports = class Application extends Emitter {constructor (options) {super (); / / omit partial code this.middleware = [];} use (fn) {if (typeof fn! = = 'function') throw new TypeError (' middleware must be a functionalities'); / / omit partial code this.middleware.push (fn); return this;}}
As you can see from the above code, the fn parameter will be type checked inside the use method. When the verification is passed, the middleware pointed to by fn will be saved to the middleware array, and the this object will be returned, thus supporting chained calls.
1.2 Task scheduling
In this article on what is worth learning from the 77.9k Axios project, Po refers to the design model of the Axios interceptor and extracts the following general task processing model:
In this general model, Po accomplishes task scheduling by placing the pre-processor and the post-processor before and after the CoreWork core task respectively. As for the middleware mechanism of Koa, it accomplishes task scheduling by placing the pre-processor and the post-processor before and after the await next () statement, respectively.
/ / Middleware app.use (async (ctx, next) = > {const start = Date.now (); await next (); const ms = Date.now ()-start; console.log (`${ctx.method} ${ctx.url}-${ms} ms`);})
1.3 Task scheduling
From the previous analysis, we already know that middleware registered with the app.use method is saved to the internal middleware array. To complete the task scheduling, we need to constantly pull the middleware from the middleware array to execute. The scheduling algorithm of the middleware is encapsulated in the compose function under the koa-compose package. The specific implementation of this function is as follows:
/ * Compose `roomleware` returning * a fully valid middleware comprised * of all those which are passed. * * @ param {Array} middleware * @ return {Function} * @ api public * / function compose (middleware) {/ / omit some codes return function (context, next) {/ / last called middleware # let index =-1; return dispatch (0); function dispatch (I) {if (I {ctx.body = 'Hello, I'm Brother Po;}); app.listen (3000)
Using the above code, I can start a server quickly. We have analyzed the use method before, so let's analyze the listen method next, and the implementation of this method is as follows:
/ / lib/application.js module.exports = class Application extends Emitter {listen (... args) {debug ('listen'); const server = http.createServer (this.callback ()); return server.listen (.. ARGs);}}
Obviously inside the listen method, the server is created by calling the createServer method of the Node.js built-in HTTP module, and then starts listening on the specified port, that is, waiting for the client to connect.
In addition, when we call the http.createServer method to create a HTTP server, the parameter we pass in is this.callback (). The specific implementation of this method is as follows:
/ / lib/application.js const compose = require ('koa-compose'); module.exports = class Application extends Emitter {callback () {const fn = compose (this.middleware); if (! this.listenerCount (' error')) this.on ('error', this.onerror); const handleRequest = (req, res) = > {const ctx = this.createContext (req, res); return this.handleRequest (ctx, fn);}; return handleRequest;}
Inside the callback method, we finally see the compose method that we haven't seen for a long time. When the callback method is called, the handleRequest function object is returned to handle the HTTP request. Whenever the Koa server receives a client request, the handleRequest method is called, where a new Context object is created, and then the registered middleware is executed to process the received HTTP request:
Module.exports = class Application extends Emitter {handleRequest (ctx, fnMiddleware) {const res = ctx.res; res.statusCode = 404; const onerror = err = > ctx.onerror (err); const handleResponse = () = > respond (ctx); onFinished (res, onerror); return fnMiddleware (ctx) .then (handleResponse) .catch (onerror);}}
OK, the content of Koa middleware has been basically introduced, and partners who are interested in the Koa kernel can study it on their own. Next, let's introduce the onion model and its application.
II. Onion model 2.1 A brief introduction to onion model
(photo Source: https://eggjs.org/en/intro/egg-and-koa.html)
In the image above, each layer within the onion represents a separate middleware for different functions, such as exception handling, cache handling, and so on. Each request will go through each layer of middleware from the left, and when it enters the innermost middleware, it will return layer by layer from the innermost middleware. So for each layer of middleware, there are two timing points to add different processing logic in a request and response cycle.
2.2 Application of Onion Model
In addition to applying the onion model in Koa, the model is also widely used in some good projects on Github, such as koa-router and Alibaba's midway, umi-request and so on.
After introducing the middleware and onion model of Koa, Po extracted the following general task processing model according to his own understanding:
The middleware described in the figure above is generally general functional code that has nothing to do with business, such as middleware used to set response time:
/ / x-response-time async function responseTime (ctx, next) {const start = new Date (); await next (); const ms = new Date ()-start; ctx.set ("X-Response-Time", ms + "ms");}
In fact, for each middleware, the front processor and the post processor are optional. For example, the following middleware is used to set uniform response content:
/ / response async function respond (ctx, next) {await next (); if ("/"! = ctx.url) return; ctx.body = "Hello World";}
Although the two middleware described above are relatively simple, you can also implement complex logic according to your own needs. The core of Koa is very light, although the sparrow has all the internal organs. By providing an elegant middleware mechanism, it allows developers to flexibly expand the functions of the Web server. This design idea is worth learning and using for reference.
At this point, the study on "how to better understand middleware and onion model" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.