一個 PHPer 第一次用 Koa2 寫 Node.js 的心路歷程

學了一段時間的 js 了,忽然想實踐一下。正好公司有個小的項目要作,就順手拿 Koa2 來作了。真是不作不知道,作了想不到。踩了一堆新手坑。javascript

初次接觸 Koa2

在知道 Koa2 以前,我也瞭解過 Express,惋惜並無實戰用過。後來你們都說 Koa 是一個比 Express 更牛X的東西,因而在好(做)奇(死)心做祟下,直接去用 Koa2 了。後來證實的確是做死,本來用 PHP 一天就能寫完東西,愣是讓我搞了三天。html

安裝

最近 Node.js V8 發佈了,原生支持 asyncawait 調用了,因此直接把 Node.js 升級了一下。java

根據 Koa2 的教程,安裝很簡單,我是使用的 yarn 的(還真是比 npm 快)。node

yarn add koa

默認就裝了 Koa 2.2。而後裝完了,其實我是一臉懵逼的,文檔上說這樣用。git

const Koa = require('koa')
const app = new Koa()
 
// response 
app.use(ctx => {
  ctx.body = 'Hello Koa'
})
 
app.listen(3000)

我照着代碼寫了下來,的確成功了。但是,難不成我要把全部的邏輯寫在 app.use 裏?github

a

中間件

我感受我受到了驚嚇,嚇得我趕忙往下看文檔。原來 Koa2 是一箇中間件模型。app.use 能夠有不少,每個 app.use 會註冊一箇中間件,這個中間件是具體作事情的。每一箇中間件是依次執行的。一個經典的洋蔥圖能夠解釋這一切。npm

那麼,上面的實例就能夠改形成這樣。json

app.use(async (ctx, next) => {
  await next()
  ctx.body = 'Hello Koa'
})

按照上面的洋蔥頭,以心爲單位,next的兩側的語句分別在洋蔥的左側和右側進行執行,頗像 Laravel 的中間件。bash

就這樣,我知道了,全部的操做沒必要寫在同一個 app.use 裏。但是,下一個問題來了,我要把全部的邏輯都寫再一個文件裏?說好的 MVC 呢?沒有 MVC 也叫作框架?Are you kidding me?(好吧後來發現原來 Koa2 並非一個裝置作網站的框架)app

既然沒有 MVC,那就本身動手豐衣足食吧。

路由

首先要處理的就是路由的問題。不過,因爲是第一次用這貨寫項目,時間緊,(僞)任務重,看了文檔後發現,原來還有一箇中間件列表的連接,裏面有各類開源的中間件。我想大家必定隔着屏幕都能聽到我發出槓鈴般的笑聲了。有一箇中間件很是棒,叫作 koa-router。這貨是這麼用的。

var Koa = require('koa')
var Router = require('koa-router')
 
var app = new Koa()
var router = new Router()
 
router.get('/', function (ctx, next) {
  // ctx.router available
});
 
app.use(router.routes())

雖然是把邏輯和 app.use 分開了,可是,好像仍是沒有解決剛纔的問題。說好的 MVC 也沒有出現。因而我再去找了找,竟然沒有 Controller 的中間件。我一下就懵逼了,玩脫了?還有一天啊個人寶貝兒。通過我半秒鐘的慎重思考,我仍是用 koa-router 本身實現一個控制器吧。

Controller

const fs = require('fs')

function addRoutes(router, routes) {
  for (let route in routes) {
    switch (route.method) {
      case: 'post':
        router.post(route.uri, route.fn)
        console.log(`Register post url: ${route.uri}`)
        break
      case: 'get':
        router.get(route.uri, route.fn)
        console.log(`Register get url: ${route.uri}`)
        break
      default: 
        console.log(`Invalid url: ${route}`)
    }
  }
}

function addControllers(router) {
  let files = fs.readdirSync(__dirname + '/controllers')

  let controllerFiles = files.filter(f => {
    return f.endsWith('.js')
  })

  for (let controllerFile in controllerFiles) {
    console.log(`process controller: ${controllerFile}...`)
    let routes = require(__dirname + '/controllers')
    addRoutes(router, routes)
  }
}

module.exports = () => {
  let router = require('koa-router')()
  addControllers(router)
  return router.routes()
}

我經過在 controllers 文件夾中,建立若干 js 文件來做爲 Controller 來使用。這裏稍微參考了下 廖雪峯的文章

而後,咱們只須要在 controllers 文件夾中添加合適的文件就能夠了。例如咱們添加一個文件叫作 chart.js ,而後這樣寫代碼。

let hello = async (ctx, next) => {
  ctx.body = 'Hello the fucking world!'
}

module.exports = [
  {
    method: 'get',
    uri: 'hello',
    fn: hello,
  }
]

最後再在 app.js 註冊中間件便可。

除此以外,咱們還須要可以處理 ctx 裏的內容,由於它裏面存儲的是原始的內容。仍是因爲時間緊,任(填)務(坑)重(急),我用了 koa-bodyparser

const bodyParser = require('koa-bodyparser')

app.use(bodyParser())

這裏要提醒的是,這貨必定要放在處理路由中間件的前面。

Model

MVCC 已經解決了,接下來就要解決 M 的問題了。這裏我用的是 Sequelize。這個 ORM 和大多數的 ORM 都差很少,因此在這裏此次沒有踩到什麼坑。我在根目錄下新建了一個 config.js 的配置文件,而後新建了 model.js 用來定義模型。

const Sequelize = require('sequelize')
const config = require('./config').databases

...

module.exports = {
  //models
}

View

視圖,我是使用了一箇中間件叫作 koa-view。因爲它使用的是 Nunjucks 模板引擎,對於寫 PHP 的我相對熟悉一點。

const view = require('koa-view')

const app = Koa()

app.use(view(__dirname + '/views'))
//controller

let Hello = (ctx, next) => {
  ctx.render('hello', datas)
}

只要在 'views' 文件夾中定義相對應的 html 文件便可。

後記

此次的嘗試,終於在個人修修補補中,搞出了一個簡陋的 MVC 模型。趕在了 deadline 前完成,真是一波三折啊。學習新技術,就是這樣,要實踐嘛= =下面給出個人項目目錄做參考

koa2/
|
+- controllers/
|  |
|  +- chart.js
|  ...
|
+- static/
|  |
|  +- js/
|     ...
|  |
|  +- style/
|     |
|     +- img
|     ...
|
+- views/
|  |
|  +- game.html
|  ...
|
+- app.js
|
+- config.js
|
+- controller.js
|
+- model.js
|
+- package.json
|
+- yarn.lock
|
+- node_modules/

菜鳥做品,若有錯誤請指正,不勝感激。

若是你喜歡個人文章,那就請我喝杯奶茶吧~

相關文章
相關標籤/搜索