Koa middleware Analysis

Source: Internet
Author: User

Reprinted Please note:Theviper http://www.cnblogs.com/TheViper

For more information, see examples.

What is Koa?

Koa was released and updated since January 1, November 2013. Compared with express, Koa is too young. however, by combining different generators (in the document), it can avoid repeated and tedious callback function nesting and greatly improve the efficiency of common error handling. Koa does not bind any middleware in the kernel method, but only provides a lightweight and elegant function.

Strictly speaking, Koa is not a complete Web framework. In actual use, developers need to use other middleware based on their own needs.

Koa only provides a middleware solution different from connect, and some simple encapsulation of request and response. This can be seen from its API. For example, for Request/login? Name = A & Pwd = B. You can use the Koa API directly. You can only use the URL and query (name = A & Pwd = B). Unlike other frameworks, further encapsulate the Request Parameters in the form of key values. In this case, other middleware such as Koa-bodyparser is required.

Other middleware may be used. For more information, see https://github.com/koajs/koa/wiki. for example,

VaR Path = require ('path') var route = require ('koa-route '); // route var Koa = require ('koa '); vaR gzip = require ('koa-gzip '); // gzip compression var staticcache = require ('koa-static-cache '); // Add headervar JSON = require ('koa-json') to the static file cache in the response '); // return the JSON response var bodyparser = require ('koa-bodyparser '); // parse the request parameter var APP = Koa (); var user_controller = require ('. /APP/controllers/usercontroller '); app. use (staticcache (path. join (_ dirname, 'public'), {maxage: 24*60*60}) app. use (bodyparser (); app. use (gzip (); app. use (route. post ('/login', new user_controller (). login); app. use (JSON ({pretty: false}); app. listen (0, 8000 );

The following describes the implementation of KOA middleware.

Usage

VaR Koa = require ('koa'); var APP = Koa (); // Add middleware 1app. use (function * (next) {var start = new date; console. log ("START = 1111"); yield next; console. log ("End ======= 1111"); var MS = new date-start; console. log ('% S % s-% s', this. method, this. URL, MS);}); // Add middleware 2app. use (function * () {console. log ("START = 2222"); this. body = 'Hello world'; console. log ("End ======= 2222") ;}); app. listen (0, 3000 ); /* Start = 1111 start = 2222end = 2222end = 2222end = 2222end = 1111get/-10 start ======= 1111 start ======= 2222end ======= 2222end ===== 1111get/favicon. ico-5 */

app.use()To add middleware. The use function accepts a generator function. This generator function is a middleware. Generator function has a parameter "Next. This next is the generator object corresponding to the next middleware generator function.yield next;Call the code of the next middleware. Specific,

Application. js

app.callback = function(){  var mw = [respond].concat(this.middleware);  var gen = compose(mw);  var fn = co.wrap(gen);  var self = this;  if (!this.listeners(‘error‘).length) this.on(‘error‘, this.onerror);  return function(req, res){    res.statusCode = 404;    var ctx = self.createContext(req, res);    onFinished(res, ctx.onerror);    fn.call(ctx).catch(ctx.onerror);  }};app.listen = function(){  debug(‘listen‘);  var server = http.createServer(this.callback());  return server.listen.apply(server, arguments);};

When listen () is executed, callback () returns the function (req, Res) callback, and then listens to the node native listen (). That is to say, the above Code is equivalent

var http = require("http");http.createServer(function(request, response) {    res.statusCode = 404;    var ctx = self.createContext(req, res);    onFinished(res, ctx.onerror);    fn.call(ctx).catch(ctx.onerror);}).listen(8888);

Next, analyze the callback,

app.use = function(fn){  assert(fn && ‘GeneratorFunction‘ == fn.constructor.name, ‘app.use() requires a generator function‘);  debug(‘use %s‘, fn._name || fn.name || ‘-‘);  this.middleware.push(fn);  return this;};

App. Use Only adds the callback generator function to the middleware array. Note that the middleware must be a generator function. For example, Koa-JSON

module.exports = function(opts){  。。。。。。。。。  return function *filter(next){    yield *next;    。。。。。。。  }};

This is also the format for writing middleware. In the Startup File, Koa-JSON () returns the generator function.

Continue with callback () callback

app.callback = function(){  var mw = [respond].concat(this.middleware);  var gen = compose(mw);  var fn = co.wrap(gen);  var self = this;  if (!this.listeners(‘error‘).length) this.on(‘error‘, this.onerror);  return function(req, res){    res.statusCode = 404;    var ctx = self.createContext(req, res);    onFinished(res, ctx.onerror);    fn.call(ctx).catch(ctx.onerror);  }};

First, add the response to the middleware array, and the response is also written in the form of generator function. Pay attention to the order of the middleware in the array, and you can see the purpose of doing so later. Then compose (MW) uses the Koa-compose module.

function compose(middleware){  return function *(next){    var i = middleware.length;    var prev = next || noop();    var curr;    while (i--) {      curr = middleware[i];      prev = curr.call(this, prev);    }    yield *prev;  }}

As you can see, the function of compose is to input the next parameter of each middleware into the generator function of the next middleware according to their order in the array, which is a bit like a linked list. Compose (MW) returns generator.

Then Co. wrap (Gen); Koa of the new vertex uses co 4.X, Co 4. X adds the wrap () method based on promise, which converts the generator function into Promise for CO to use.

Koa of the old vertex is 0.8.1, where var fn = Co (Gen );

Self. createcontext (req, Res); In the callback, pass the native request and response of node into Koa and encapsulate it.

Onfinished (Res, CTX. onerror);, onfinished is a specially encapsulated module when the request is closed, completed, or error occurs, which is not discussed here.

FN. Call (CTX). Catch (CTX. onerror);, start to execute CO (Gen )().

In the CO analysis, the first gen. next (). next () will be executed only after the asynchronous operation is successful, but the above source code cannot find the statement like next. Why?

The reason is that yield statements target objects. If yield generator function is used, the code will go in step by step. If yield generator function is still available after step by step, continue to step in ., Without the use of gen. Next (), the code is automatically entered in a single step. If there is a yield non-function, such as yield 'end', it is equivalent to setting a breakpoint there, and the code will temporarily stop there. At this time, gen. Next () is required to continue to execute the following code.

The example in CO analysis contains statements such as yield 'start' and yield 'end'. Therefore, multiple gen. Next () statements are required to complete the program execution.

The following is an example of yield generator function.

function* run1() {console.log("step in child generator1")console.log("step out child generator1")}function* run() {console.log("step in child generator")var b=yield *run1();console.log("step out child generator")}function* start() {  yield *run();  return ‘over‘;}var it = start();console.log(it.next());

Result

We can see that all the generator functions are executed after only one next () is used.

After understanding this, let's look at compose again. It starts from the final middleware of the array. As long as yield is encountered, it goes in one step, because all the middleware is in the form of generator function, so as long as next () is the first time, it will execute to the end, that is, it will execute the middleware without the yield next statement, and then return the original path. It is like

Source: http://purplebamboo.github.io/2014/05/24/koa-source-analytics-3/

Note that yield * Prev in Compose (). At this time, I = 0, and Prev is * response ().

function *respond(next) {  yield *next;  .............}

As you can see, yield * Next is at the very beginning, and will be placed into the next middleware .... The following process is clearly illustrated in the figure above.

I have to say that the code from compose to CO is not complicated at all, but the combination is a very clever design!

Koa middleware Analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.