Koa2核心原理

解析Koa2核心原理(手寫KOA框架并解析)

前言:
相對(duì)于express框架寺庄,koa框架只是提供了async/await 的語法應(yīng)用族沃,大致上邏輯是相同的甚纲!

文章主要分為三個(gè)部分:

  1. koa2創(chuàng)建服務(wù)
  2. async/await 語法
  3. 自己寫個(gè)koa2

一:koa2
使用koa2創(chuàng)建服務(wù)

/**
 * koa2 中間件原理
 *1. app.use 先將注冊(cè)的中間件收集起來
 *2.實(shí)現(xiàn)next。上一個(gè)通過next實(shí)現(xiàn)觸發(fā)執(zhí)行下一個(gè)楞件,
 * 等await后面的的函數(shù)執(zhí)行完了在執(zhí)行剩下的語句
 */
const Koa = require('koa');
const app = new Koa();

// 注冊(cè)中間件

// logger
app.use(async (ctx, next) => {
  await next();
  console.log('第一個(gè)中間件 結(jié)束')
});

app.use(async (ctx, next) => {
  await next();
  console.log('第二個(gè)中間件 結(jié)束')
});

// response
app.use(async ctx => {
  ctx.body = 'Hello World';
  console.log('第三個(gè)中間件 結(jié)束')
});


//監(jiān)聽
app.listen(8000);

通過以上代碼可以知道兴蒸,我們先執(zhí)行第一個(gè)中間件视粮,遇到next呢细办,然后去執(zhí)行第二個(gè)中間件橙凳,等后面的中間件都執(zhí)行ok后,await解禁笑撞,執(zhí)行第一個(gè)中間件的剩下的語句

二: async/await 語法
通常在異步的時(shí)候岛啸,我們都會(huì)使用Promise來,但是了多層的嵌套出現(xiàn)問題茴肥,那么如何讓異步“同步化”坚踩?這里是使用 async/await的語法,當(dāng)然瓤狐,返回的是promise對(duì)象


/**
 * async timeout(){
 *   return "hello world"
 *   throw new Error('rejected');
 * }
 *
 * 其 也是函數(shù)瞬铸,所以,直接調(diào)用础锐,但是嗓节,返回的是promise對(duì)象
 *timeout()  =====>promise
 *
 * 如果有正確的返回值,那么就調(diào)用promise.solve(data)
 * 如果返回錯(cuò)誤信息皆警, promise.reject(data)
 *
 * 我們想要在里面執(zhí)行異步函數(shù)讀取數(shù)據(jù)拦宣,
 *  await promise
 *  為了防止錯(cuò)誤,一般我們會(huì)try catch 包裹
 */

三:自己寫KOA2框架

const http = require('http');


class IKoa {
  constructor() {
    this.middlewareList = [];
  }

  /**
   * 收集 async中間件
   */
  use(fn){
      this.middlewareList.push(fn)
  }


  //創(chuàng)建上下文,組合相關(guān)的請(qǐng)求來和去的數(shù)據(jù)
  createContext(req,res){
    const ctx ={
      req,
      res
    }
    ctx.body = (data) => {
      let _d = data;
      if(typeof _d != 'string'){
        _d = JSON.stringify(_d)
      }
      res.end(_d)
    }
    return ctx;
  }

  //組合中間件,定義next方法
  compose(middlewareList){
    return function(ctx){
      // ctx.body({
      //   name:"a"
      // })
       function next(i) {
              //取出一個(gè)中間件
              const fn = middlewareList[i]
              if(fn){
                //next.bind(null,i+1)  = = next() 執(zhí)行下一個(gè)中間件
                
                //這里也就是執(zhí)行中間件函數(shù)  dispatch相當(dāng)于next
                fn(ctx, next.bind(null, i + 1))  // promise
              }
        }
        //先執(zhí)行第一個(gè)
        return next(0)
    }
  }
  /**
   * 上下文
   * @param  {[type]}   ctx
   * @param  {Function} fn  第一個(gè)中間件
   * @return  fn 這里返回一個(gè)fn
   */
  handleRequest(ctx,fn){
      return fn(ctx)
  }

  callback(){
    //獲取第一個(gè)中間件
    const fn = this.compose(this.middlewareList)
    return (req,res) => {
        const ctx = this.createContext(req,res);
        //這里返回第一個(gè)中間件鸵隧,作為callback的返回
        return this.handleRequest(ctx,fn)
    }
  }

  listen(...agrus){
    //這里的核心绸罗,callback 返回是執(zhí)行的第一個(gè)中間件,通過第一個(gè)中間件去next下一個(gè)中間件
    const server = http.createServer(this.callback());
    server.listen(...agrus)
  }
}
module.exports = IKoa

通過以上代碼豆瘫,可以看出珊蟀,callback返回的是第一個(gè)中間件的函數(shù)的組裝函數(shù),在這個(gè)組裝函數(shù)里面先執(zhí)行自身外驱,其參數(shù)是ctx上下文系洛,和下一個(gè)中間件函數(shù),其實(shí)next也就是下一個(gè)中間件函數(shù)略步,那么執(zhí)行next就相當(dāng)于執(zhí)行下一個(gè)中間件描扯,當(dāng)然,返回的是Promise趟薄,那么就可以用await接收

測(cè)試使用:

const Koa = require('./i-koa');
const app = new Koa();

app.use( async (ctx, next) => {
  // ctx.body("111")
  next()
  console.log("111");
})
app.use( async (ctx, next) => {
  ctx.body("222")

})

app.listen(9000,()=>{
  console.log("啟動(dòng)了");
})


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绽诚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杭煎,更是在濱河造成了極大的恐慌恩够,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,332評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羡铲,死亡現(xiàn)場(chǎng)離奇詭異蜂桶,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)也切,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門扑媚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雷恃,你說我怎么就攤上這事疆股。” “怎么了倒槐?”我有些...
    開封第一講書人閱讀 157,812評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵旬痹,是天一觀的道長。 經(jīng)常有香客問我讨越,道長两残,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,607評(píng)論 1 284
  • 正文 為了忘掉前任把跨,我火速辦了婚禮人弓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘节猿。我一直安慰自己票从,他們只是感情好漫雕,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,728評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著峰鄙,像睡著了一般浸间。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吟榴,一...
    開封第一講書人閱讀 49,919評(píng)論 1 290
  • 那天魁蒜,我揣著相機(jī)與錄音,去河邊找鬼吩翻。 笑死兜看,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狭瞎。 我是一名探鬼主播细移,決...
    沈念sama閱讀 39,071評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼熊锭!你這毒婦竟也來了弧轧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,802評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤碗殷,失蹤者是張志新(化名)和其女友劉穎精绎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锌妻,經(jīng)...
    沈念sama閱讀 44,256評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡代乃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,576評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仿粹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搁吓。...
    茶點(diǎn)故事閱讀 38,712評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖牍陌,靈堂內(nèi)的尸體忽然破棺而出擎浴,到底是詐尸還是另有隱情员咽,我是刑警寧澤毒涧,帶...
    沈念sama閱讀 34,389評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站贝室,受9級(jí)特大地震影響契讲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜滑频,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,032評(píng)論 3 316
  • 文/蒙蒙 一捡偏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧峡迷,春花似錦银伟、人聲如沸你虹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傅物。三九已至,卻和暖如春琉预,著一層夾襖步出監(jiān)牢的瞬間董饰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評(píng)論 1 266
  • 我被黑心中介騙來泰國打工圆米, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卒暂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,473評(píng)論 2 360
  • 正文 我出身青樓娄帖,卻偏偏與公主長得像也祠,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子近速,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,606評(píng)論 2 350