Koa, created by the original Express team, is committed to becoming a smaller, stronger and more expressive web framework. Using koa to write web applications, by combining different generators, you can eliminate duplicate and cumbersome callback function nesting and greatly improve the efficiency of common error handling. Koa does not bind any middleware in kernel methods, it only provides a lightweight and elegant library of functions, making writing web applications easy to use.
Install koa
koa depends on a Node environment that supports generator, that is, the version of node must be 0.11.9 or higher, otherwise it will not be executed.
Use npm:
$ npm install koa
Or, select Install globally:
$ npm install -g koa
Example
Here is a simple example of koa:
var koa = require('koa');var app = koa();// loggerapp.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms);});// responseapp.use(function *(){ this.body = 'Hello World';});app.listen(3000);Unlike normal functions, generator functions are declared as function*. Functions declared with this keyword support yield. The usage and significance of yield will be discussed later.
Execute koa
When executing koa, you need to run in -harmony mode. For convenience, you can set node as the alias for starting harmony mode by default:
alias node='node --harmony'
This way, you can use it directly when executing related js.
Cascading
This is a relatively abstract concept. Koa middleware is cascading in a very traditional way, which is what is called Cascading here.
In previous Node development, frequent use of callbacks was not convenient to show complex code logic. In Koa, we can write truly expressive middleware. Compared with Connect's method to implement middleware, Koa's approach is not simply to hand over control to middleware after middleware until the program ends. Koa executes code like a paper clip. When the user requests to pass the middleware, it will be passed to the next route that meets the request (downstream). When yield next cannot capture the next middleware, it returns in reverse order to continue executing the code (upstream).
The following example shows the Hello World example written using this special method: At the beginning, the user's request passes through the x-response-time middleware and the logging middleware. These two middlewares record some request details, and then "passes through" the response middleware once, finally end the request and return to "Hello World".
When the program runs to yield next, the code flow will pause the execution of the remaining code of the middleware and switch to the next defined middleware to execute the code. This way of switching control is called downstream. When there is no next middleware to execute downstream, the code will be executed in reverse order.
var koa = require('koa');var app = koa();// x-response-timeapp.use(function *(next){ // (1) Enter the route var start = new Date; yield next; // (5) Enter the x-response-time middleware again and record the time "traveled" through this middleware var ms = new Date - start; this.set('X-Response-Time', ms + 'ms'); // (6) Return this.body});// loggerapp.use(function *(next){ // (2) Enter logger middleware var start = new Date; yield next; // (4) Enter the logger middleware again and record the time when it "travels" through this middleware twice var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms);});// responseapp.use(function *(){ // (3) Enter the response middleware, and the next middleware that meets the conditions is not captured, and passed to upstream this.body = 'Hello World';});app.listen(3000);In the example code above, the middleware has been marked in the comments in the order in which it is executed. You can also try running this example yourself and print and record the output and time-consuming of each link.
.middleware1 { // (1) do some stuff .middleware2 { // (2) do some other stuff .middleware3 { // (3) NO next yield ! // this.body = 'hello world' } // (4) do some other stuff later } // (5) do some stuff lastest and return}The execution order of the middleware is marked in the pseudo-code above. Does it look a bit like the yield when ruby executes a block? Maybe this will help you better understand how koa works.
koa access mysql database operation
Implementation method one (co-mysql)
The mysql library is implemented in the form of callbacks, while the koa middleware requires the form of Promise. After searching, we found that co-mysql and mysql-co. The two libraries have similar ideas. Mysql-co has a higher encapsulation degree and uses the faster mysql2, while co-mysql is simpler, just encapsulating mysql.query into the form of Promise. The following is the writing method based on co-mysql
var wrapper = require('co-mysql'), mysql = require('mysql');var options = { host : 'localhost', port : 3306, database : 'test', user: 'root', password : 'rootroot'};var pool = mysql.createPool(options), p = wrapper(pool);... var rows = yield p.query('SELECT 1'); yield this.render('index', { title: rows[0].fieldName });...})();Implement method two (promisify-node)
Find the promisify-node library, and you can convert the library into a Promise form as a whole. The sample code is as follows:
var promisify = require("promisify-node");var db = promisify("myDbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...Implementation method three (thunkify, thunkify-wrap)
Encapsulation can also be completed using thunkify. thunkify-wrap is an enhanced version of thunkify. However, according to the explanation, this method may be eliminated in future development. The approximate use is as follows:
var genify = require('thunkify-wrap').genify;var db = genify("myDbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...Implementation Method Four (Direct Method)
Directly transform the original code under express into a Promise form, refer to co-mysql, and carefully learn the relevant knowledge of Promise, and complete the transformation of existing code. The code and description are as follows:
dbHelper.js
var config = require('./dbconfig');var options = { 'host': config.db_host, 'port': config.db_port, 'database': config.db_name, 'user': config.db_user, 'password': config.db_passwd}var mysql = require('mysql');var pool = mysql.createPool(options);//Internal encapsulation of mysql, execute sql statement function execQuery(sql, values, callback) { var errinfo; pool.getConnection(function(err, connection) { if (err) { errinfo = 'DB-get database connection exception!'; throw errinfo; } else { var querys = connection.query(sql, values, function(err, rows) { release(connection); if (err) { errinfo = 'DB-SQL statement execution error:' + err; callback(err); } else { callback(null,rows); //Note: the first parameter must be null } }); } });}function release(connection) { try { connection.release(function(error) { if (error) { console.log('DB-close database connection exception!'); } }); } catch (err) {}}//Return the Promise function form to the external interface exports.getById = function(tablename, id){ return new Promise(function(resolve, reject){ var values = {id:id}; var sql = 'select * from ?? where ?'; execQuery(sql,[tablename, values], function(err, rows){ if(err){ reject(err); }else{ resolve(rows); } }) });}routes/index.jsvar db = require("../dbHelper");...var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName });...Code
Please refer to the database operation section in this project. The project is in continuous development and the database example section is taken from this project.
https://github.com/zhoutk/koadmin.git