本節(jié)我們將簡單介紹一下 koa。
nodejs是什么?
Node.js是一個創(chuàng)建于 2009年的Javascript運(yùn)行環(huán)境。它使用了一個事件驅(qū)動、非阻塞式 I/O 的模型,基于回調(diào)實現(xiàn)的異步編程,使其輕量又高效。
例如,我們可以一邊讀取文件,一邊執(zhí)行其他命令,在文件讀取完成后,我們將文件內(nèi)容作為回調(diào)函數(shù)的參數(shù)返回。這樣在執(zhí)行代碼時就沒有阻塞或等待文件 I/O 操作。
這就大大提高了 Node.js 的性能,可以處理大量的并發(fā)請求,因此,Node 主要用在開發(fā) Web 應(yīng)用。
使用原生nodejs提供web服務(wù)
要在nodejs中提供web服務(wù),我們需要引入 nodejs 的Http模塊:require('http'), 然后調(diào)用createServer方法,傳入一個函數(shù)作為參數(shù)即可:
const Server = http.createServer((req, res) => {
res.writeHead(200,{'Content-Type': 'application/json;charset=utf-8;'});
res.write('{text: "寫代碼很快樂啊!"}');
res.end();
}).listen(8888);
可以看到,代碼可讀性不是很好,開發(fā)也不是很便利,于是就有了 Express 這個第一代最流行的web框架。
express 框架
我們看看,使用express, 怎么實現(xiàn)一個最簡單的入門網(wǎng)站:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('寫代碼很快樂!');
});
app.listen(8888);
可以看到,代碼精簡了很多,雖然express的API很簡單,但是它是基于ES5的語法,要實現(xiàn)異步代碼,只有一個方法:回調(diào)。如果異步嵌套層次過多,代碼寫起來就非常難看,比如讀取一個文件成功后再讀取一個文件:
app.get('/file', function (req, res) {
fs.readFile('/file1', function (err, data) {
if (err) { res.status(500).send('讀取文件1失敗'); }
fs.readFile('/file2', function (err, data) {
if (err) { res.status(500).send('讀取文件2失敗'); }
res.type('text/plain');
res.send(data);
});
});
});
雖然可以用async這樣的庫來組織異步代碼,但是用回調(diào)寫異步實在是太痛苦了,特別是異步嵌套多的時候,這就是JS遠(yuǎn)古時期的 回調(diào)地獄!
koa 1.x的到來
隨著ES6在新版Node.js獲得支持ES6,express的團(tuán)隊基于ES6的generator推出了koa這個 web 框架。和express相比,koa 1.0使用generator實現(xiàn)異步,比如實現(xiàn)上面同樣的功能,代碼如下:
var koa = require('koa');
var app = koa();
app.use('/file', function *() {
yield readFile1();
var data = yield readFile2();
this.body = data;
});
app.listen(8888);
可以看到,用generator實現(xiàn)異步比回調(diào)簡單了不少,但是generator的本意并不是異步。Promise才是為異步設(shè)計的,但是Promise的寫法很復(fù)雜。為了簡化異步代碼,ES7引入了新的關(guān)鍵字async和await,可以輕松地把一個function變?yōu)楫惒侥J剑?/p>
async function () {
var data = await fs.read('/file1');
}
最新的koa 2.x的到來
koa團(tuán)隊并沒有止步于koa 1.0,他們非常超前地基于ES7開發(fā)了koa2,和koa 1相比,koa2完全使用Promise并配合async來實現(xiàn)異步。
app.use(async (ctx, next) => {
await next();
var data = await readFile();
ctx.response.type = 'text/plain';
ctx.response.body = data;
});
通過以上分享,大家可以看到,我們項目使用koa2,是按照node->express->koa1-<koa2 一步步隨著新的JS規(guī)范通過并獲得支持的發(fā)展而來的,出現(xiàn)的主要原因就是為了在node開發(fā)中優(yōu)雅的寫異步代碼。
express, koa1和koa2的區(qū)別
koa vs express
-
相同點
- 構(gòu)建 web 應(yīng)用的 node 框架
- 總體來看語法差別不大,比如都是引入后框架后實例后,中間件處理以及監(jiān)聽端口;
- 都是同一個團(tuán)隊開發(fā)維護(hù)的
-
區(qū)別
- express: 框架內(nèi)容更豐富,有更大的社區(qū),歷史更悠久,文檔更豐富,用戶群更大,支持 jade 等前端模板語言,express沒有統(tǒng)一的錯誤處理,而koa有默認(rèn)的錯誤處理方式。
- koa: 更小、更富有表現(xiàn)力、更健壯,Koa 支持 es6 語法,Koa 在內(nèi)核方法中不綁定任何中間件,不提供路由功能和某些工具,摒棄了的回調(diào),采用 generator 或 promise的方式,在 Context中,Koa 對 request 和 response 進(jìn)行了封裝,使用方式也相應(yīng)改變,如返回簡單內(nèi)容,在koa: this.body = ‘hello world’,而在express: res.send(‘hello world’)。
koa1 vs koa2
- 中間件的使用: koa1依賴 co 并采用 generator 函數(shù),在函數(shù)內(nèi)使用 yield 語句,而koa2增加了箭頭函數(shù),移除了 co 依賴,使用 Promise,因此可以結(jié)合 async,await 使用;
- context 對象的獲?。簁oa1為this 對象,this.req, this.res;koa2: cxt 參數(shù),cxt.req, cxt.res。
了解了koa的背景知識后,下一節(jié)我們將簡單分析其源碼啦!