Node.js的Koa框架上手及MySQL操作指南
由 Express 原班人馬打造的 koa,致力于成為一個(gè)更小、更健壯、更富有表現(xiàn)力的 Web 框架。使用 koa 編寫 web 應(yīng)用,通過組合不同的 generator,可以免除重復(fù)繁瑣的回調(diào)函數(shù)嵌套,并極大地提升常用錯(cuò)誤處理效率。Koa 不在內(nèi)核方法中綁定任何中間件,它僅僅提供了一個(gè)輕量?jī)?yōu)雅的函數(shù)庫(kù),使得編寫 Web 應(yīng)用變得得心應(yīng)手。
安裝koa
koa 依賴支持 generator 的 Node 環(huán)境,也就是說,node的版本要在 0.11.9 或者更高,否則將無法執(zhí)行。
用npm:
$ npm install koa
或者,選擇安裝在全局:
$ npm install -g koa
Example
這是一個(gè)koa的簡(jiǎn)單例子:
var koa = require('koa'); var app = koa(); // logger app.use(function *(next){ var start = new Date; yield next; var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms); }); // response app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
與普通的 function 不同,generator functions 以 function* 聲明。以這種關(guān)鍵詞聲明的函數(shù)支持 yield。在后面會(huì)講到 yield 的用法和意義。
執(zhí)行koa
執(zhí)行koa時(shí)需要在 —-harmony 模式下運(yùn)行,為了方便可以將 node 設(shè)置為默認(rèn)啟動(dòng) harmony 模式的別名:
alias node='node --harmony'
這樣在執(zhí)行相關(guān)js的時(shí)候就可以直接使用了。
Cascading
這是一個(gè)比較抽象的概念。Koa 中間件以一種非常傳統(tǒng)的方式級(jí)聯(lián)起來,也就是這里所謂的Cascading。
在以往的 Node 開發(fā)中,頻繁使用回調(diào)不太便于展示復(fù)雜的代碼邏輯,在 Koa 中,我們可以寫出真正具有表現(xiàn)力的中間件。與 Connect 實(shí)現(xiàn)中間件的方法相對(duì)比,Koa 的做法不是簡(jiǎn)單的將控制權(quán)依次移交給一個(gè)又一個(gè)的中間件直到程序結(jié)束,Koa 執(zhí)行代碼的方式有點(diǎn)像回形針,用戶請(qǐng)求通過中間件,遇到 yield next 關(guān)鍵字時(shí),會(huì)被傳遞到下一個(gè)符合請(qǐng)求的路由(downstream),在 yield next 捕獲不到下一個(gè)中間件時(shí),逆序返回繼續(xù)執(zhí)行代碼(upstream)。
下邊這個(gè)例子展現(xiàn)了使用這一特殊方法書寫的 Hello World 范例:一開始,用戶的請(qǐng)求通過 x-response-time 中間件和 logging 中間件,這兩個(gè)中間件記錄了一些請(qǐng)求細(xì)節(jié),然后「穿過」 response 中間件一次,最終結(jié)束請(qǐng)求,返回 「Hello World」。
當(dāng)程序運(yùn)行到 yield next 時(shí),代碼流會(huì)暫停執(zhí)行這個(gè)中間件的剩余代碼,轉(zhuǎn)而切換到下一個(gè)被定義的中間件執(zhí)行代碼,這樣切換控制權(quán)的方式,被稱為 downstream,當(dāng)沒有下一個(gè)中間件執(zhí)行 downstream 的時(shí)候,代碼將會(huì)逆序執(zhí)行。
var koa = require('koa'); var app = koa(); // x-response-time app.use(function *(next){ // (1) 進(jìn)入路由 var start = new Date; yield next; // (5) 再次進(jìn)入 x-response-time 中間件,記錄2次通過此中間件「穿越」的時(shí)間 var ms = new Date - start; this.set('X-Response-Time', ms + 'ms'); // (6) 返回 this.body }); // logger app.use(function *(next){ // (2) 進(jìn)入 logger 中間件 var start = new Date; yield next; // (4) 再次進(jìn)入 logger 中間件,記錄2次通過此中間件「穿越」的時(shí)間 var ms = new Date - start; console.log('%s %s - %s', this.method, this.url, ms); }); // response app.use(function *(){ // (3) 進(jìn)入 response 中間件,沒有捕獲到下一個(gè)符合條件的中間件,傳遞到 upstream this.body = 'Hello World'; }); app.listen(3000);
在上方的范例代碼中,中間件以此被執(zhí)行的順序已經(jīng)在注釋中標(biāo)記出來。你也可以自己嘗試運(yùn)行一下這個(gè)范例,并打印記錄下各個(gè)環(huán)節(jié)的輸出與耗時(shí)。
.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 }
上方的偽代碼中標(biāo)注了中間件的執(zhí)行順序,看起來是不是有點(diǎn)像 ruby 執(zhí)行代碼塊(block)時(shí) yield 的表現(xiàn)了?也許這能幫助你更好的理解 koa 運(yùn)作的方式。
koa訪問mysql數(shù)據(jù)庫(kù)操作
實(shí)現(xiàn)方法一(co-mysql)
mysql庫(kù)是以回調(diào)形式實(shí)現(xiàn)的,而koa中間件要求Promise形式,經(jīng)過搜索,發(fā)現(xiàn)了co-mysql和mysql-co,這兩個(gè)庫(kù)的思路差不多,mysql-co封裝度更高,并使用速度更快的mysql2,而co-mysql更簡(jiǎn)單,只是將mysql.query封裝成Promise形式。下面是基于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 }); ... })();
實(shí)現(xiàn)方法二(promisify-node)
找到promisify-node庫(kù),可以將庫(kù)整體轉(zhuǎn)化為Promise形式,示例代碼如下:
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 }); ...
實(shí)現(xiàn)方法三(thunkify、thunkify-wrap)
使用thunkify也能夠完成封裝,thunkify-wrap是一個(gè)增強(qiáng)版的thunkify,不過看說明,這種方法在未來的發(fā)展中可能會(huì)被淘汰,大概的使用如下:
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 }); ...
實(shí)現(xiàn)方法四(直接方法)
直接改造原來express下的代碼為Promise形式,參考了co-mysql,并仔細(xì)學(xué)習(xí)了Promise相關(guān)知識(shí),完成了已有代碼的改造,代碼及說明如下:
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); //內(nèi)部對(duì)mysql的封裝,執(zhí)行sql語句 function execQuery(sql, values, callback) { var errinfo; pool.getConnection(function(err, connection) { if (err) { errinfo = 'DB-獲取數(shù)據(jù)庫(kù)連接異常!'; throw errinfo; } else { var querys = connection.query(sql, values, function(err, rows) { release(connection); if (err) { errinfo = 'DB-SQL語句執(zhí)行錯(cuò)誤:' + err; callback(err); } else { callback(null,rows); //注意:第一個(gè)參數(shù)必須為null } }); } }); } function release(connection) { try { connection.release(function(error) { if (error) { console.log('DB-關(guān)閉數(shù)據(jù)庫(kù)連接異常!'); } }); } catch (err) {} } //對(duì)外接口返回Promise函數(shù)形式 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.js var db = require("../dbHelper"); ... var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName }); ...
代碼
請(qǐng)參考這個(gè)項(xiàng)目中的數(shù)據(jù)庫(kù)操作部分,項(xiàng)目處于持續(xù)開發(fā)中,數(shù)據(jù)庫(kù)示例部分取自該項(xiàng)目。
https://github.com/zhoutk/koadmin.git
- Node.js?網(wǎng)絡(luò)框架koa?compose中間件使用解析
- 如何從頭實(shí)現(xiàn)一個(gè)node.js的koa框架
- node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲練習(xí)
- 利用Node.js+Koa框架實(shí)現(xiàn)前后端交互的方法
- 淺談Koa2框架利用CORS完成跨域ajax請(qǐng)求
- nuxt框架中路由鑒權(quán)之Koa和Session的用法
- 使用webpack打包koa2 框架app
- 基于Koa(nodejs框架)對(duì)json文件進(jìn)行增刪改查的示例代碼
- koa框架的原理、功能,與基本使用方法概述
相關(guān)文章
Node.js開發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證功能
這篇文章主要介紹了Node.js開發(fā)教程之基于OnceIO框架實(shí)現(xiàn)文件上傳和驗(yàn)證的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11nodejs使用socket5進(jìn)行代理請(qǐng)求的實(shí)現(xiàn)
這篇文章主要介紹了nodejs使用socket5進(jìn)行代理請(qǐng)求的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02nodejs服務(wù)內(nèi)存泄露排查過程和優(yōu)化方法
在開發(fā)和部署Node.js應(yīng)用程序時(shí),內(nèi)存泄露是一個(gè)常見的挑戰(zhàn),本文將探討如何對(duì)于一個(gè)陌生項(xiàng)目進(jìn)行內(nèi)存排查和優(yōu)化的方法,文章通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11nodejs實(shí)現(xiàn)OAuth2.0授權(quán)服務(wù)認(rèn)證
本篇文章主要介紹了nodejs實(shí)現(xiàn)OAuth2.0授權(quán)服務(wù)認(rèn)證,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12Node.js 使用流實(shí)現(xiàn)讀寫同步邊讀邊寫功能
本文通過代碼給大家介紹了Node.js 使用流實(shí)現(xiàn)讀寫同步邊讀邊寫功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的額朋友參考下吧2017-09-09基于Node.js的強(qiáng)大爬蟲 能直接發(fā)布抓取的文章哦
基于Node.js的強(qiáng)大爬蟲能直接發(fā)布抓取的文章哦!本爬蟲源碼基于WTFPL協(xié)議,感興趣的小伙伴們可以參考一下2016-01-01