最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

koa中間件核心(koa-compose)源碼解讀分析

 更新時間:2020年06月15日 09:07:53   作者:零信號  
這篇文章主要介紹了koa中間件核心(koa-compose)源碼解讀分析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

最近經(jīng)常使用koa進(jìn)行服務(wù)端開發(fā),迷戀上了koa的洋蔥模型,覺得這玩意太好用了。而且koa是以精簡為主,沒有很多集成東西,所有的東西都需按需加載,這個更是太合我胃口了哈哈哈哈。

相對與express的中間件,express的中間件使用的是串聯(lián),就像冰糖葫蘆一樣一個接著一個,而koa使用的V型結(jié)構(gòu)(洋蔥模型),這將給我們的中間件提供更加靈活的處理方式。

基于對洋蔥模型的熱衷,所以對koa的洋蔥模型進(jìn)行一探究竟,不管是koa1還是koa2的中間件都是基于koa-compose進(jìn)行編寫的,這種V型結(jié)構(gòu)的實現(xiàn)就來源于koa-compose。
附上源碼先:

function compose (middleware) {
 // 參數(shù)middleware 是一個中間件數(shù)組,存放我們用app.use()一個個串聯(lián)起來的中間件
 // 判斷中間件列表是否為數(shù)組,如果不為數(shù)組,則拋出類型錯誤
 if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
 // 判斷中間件是否為函數(shù),如果不為函數(shù),則拋出類型錯誤
 for (const fn of middleware) {
  if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
 }

 /**
 1. @param {Object} context
 2. @return {Promise}
 3. @api public
  */
 
 return function (context, next) {
  // 這里next指的是洋蔥模型的中心函數(shù)
  // context是一個配置對象,保存著一些配置,當(dāng)然也可以利用context將一些參數(shù)往下一個中間傳遞
   
  // last called middleware #
  let index = -1 // index是記錄執(zhí)行的中間件的索引
  return dispatch(0) // 執(zhí)行第一個中間件 然后通過第一個中間件遞歸調(diào)用下一個中間件
  
  function dispatch (i) {
   // 這里是保證同個中間件中一個next()不被調(diào)用多次調(diào)用 
   // 當(dāng)next()函數(shù)被調(diào)用兩次的時候,i會小于index,然后拋出錯誤
   if (i <= index) return Promise.reject(new Error('next() called multiple times'))
   index = i
   let fn = middleware[i] // 取出要執(zhí)行的中間件
   if (i === middleware.length) fn = next // 如果i 等于 中間件的長度,即到了洋蔥模型的中心(最后一個中間件)
   if (!fn) return Promise.resolve() // 如果中間件為空,即直接resolve
   try {
    // 遞歸執(zhí)行下一個中間件 (下面會重點分析這個)
    return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
   } catch (err) {
    return Promise.reject(err)
   }
  }
 }
}

看到這里,如果下面的那些能夠理解,那么下面的可以不用看的,還是不能理解的就繼續(xù)往下看,詳細(xì)一點的分析。

首先,我們用app.use()添加一個中間件,在koa的源碼里app.use()這個方法就是將一個中間件push進(jìn)middleware這個中間件列表里。源碼里是這么寫的(這個比較簡單 不做分析):

 use(fn) {
  if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
  if (isGeneratorFunction(fn)) {
   deprecate('Support for generators will be removed in v3. ' +
        'See the documentation for examples of how to convert old middleware ' +
        'https://github.com/koajs/koa/blob/master/docs/migration.md');
   fn = convert(fn);
  }
  debug('use %s', fn._name || fn.name || '-');
  this.middleware.push(fn);
  return this;
 }

compose這個方法傳入一個中間件列表middleware,這個列表就是我們使用use()添加進(jìn)去的方法列表,首先會判斷列表是否為數(shù)組,中間件是否為方法,如果不是就直接拋出類型錯誤。

  1. compose返回的是一個函數(shù),這里使用閉包來緩存中間件列表,然后這個函數(shù)接收兩個參數(shù),第一個參數(shù)是context,是一個存放配置信息的對象。第二份參數(shù)是一個next方法,也是洋蔥模型的中心或者說是V型模型的拐點。
  2. 創(chuàng)建一個index變量來保存執(zhí)行的中間件索引,然后從第一個中間件開始開始遞歸執(zhí)行。
let index = -1
return dispatch(0)

dispatch方法就是執(zhí)行中間件,先判斷索引,如果i小于index那么說明在同一個中間件里執(zhí)行了兩次或兩次以上的next函數(shù),如果i>index則說明該中間件還未執(zhí)行,那么將該中間件的所以記錄下來

if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i

取出該中間件,如果i等于中間件的長圖,則說明執(zhí)行到了洋蔥模型的中心,則最后一個中間件,如果中間件為空,那么就直接resovle掉

    let fn = middleware[i]
    if(i === middleware.length){
     fn = next
    }
    if(!fn){
      return Promise.resolve()
    }

到了最刺激的部分了,也是有點繞的部分了,首先為啥return的是一個Promise的對象(Promise.resolve也是一個promise對象)呢,因為我們await next()的時候,await是等待且執(zhí)行一個async函數(shù)的完成,async會默認(rèn)返回一個promise對象,所以這里return的是一個promise對象。我們在每個中間里面await mext() next()指的就是下一個中間件,也就是

fn(context, function next () {
      return dispatch(i + 1)
     })

所以我們上一個中的await 等待的就是dispatch(i+1)的執(zhí)行完成,dispatch返回的是Promise.resolve(fn(context, function next () { xxxx })),這樣來看雖然一開始只執(zhí)行了dispatch(0),但是是由這個函數(shù)形成了一條執(zhí)行鏈。

以三個中間件執(zhí)行為例,dispatch(0)執(zhí)行后就形成:

Promise.resolve( // 第一個中間件
 function(context,next){ // 這里的next第二個中間件也就是dispatch(1)
   // await next上的代碼 (中間件1)
  await Promise.resolve( // 第二個中間件
   function(context,next){ // 這里的next第二個中間件也就是dispatch(2)
     // await next上的代碼 (中間件2)
    await Promise.resolve( // 第三個中間件
     function(context,next){ // 這里的next第二個中間件也就是dispatch(3)
       // await next上的代碼 (中間件3)
      await Promise.resolve()
      // await next下的代碼 (中間件3)
     }
    )
     // await next下的代碼 (中間件2)
   }
  )
   // await next下的代碼 (中間件2)
 }
) 

先執(zhí)行await上面的代碼,然后等待最后一個中間件resolve一個個往上傳遞,這就形成了一個洋蔥模型。
最后附上測試代碼:

async function test1(ctx, next) {
  console.log('中間件1上');
  await next();
  console.log('中間件1下');
 };
 
 async function test2(ctx, next) {
  console.log('中間件2上');
  await next();
  console.log('中間件2下');
 };
 
 async function test3(ctx, next) {
  console.log('中間件3上');
  await next();
  console.log('中間件3下');
 };
 let middleware = [test1, test2, test3];
 
 let cp = compose(middleware);
 
 cp('ctx', function() {
  console.log('中心');
 });

OK,到這里koa2的中間件核心(koa-compose)就解析完成了,一開始看的時候,也被繞了好久,多看幾遍多分析一步一步捋順。koa1的中間件等過幾天有時間再補上吧,koa1是基于generator,源碼比起koa2相對簡單。

最近在看koa2源碼,等有時間再繼續(xù)更新koa一些源碼的分析。

到此這篇關(guān)于koa中間件核心(koa-compose)源碼解讀分析的文章就介紹到這了,更多相關(guān)koa中間件核心內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Node.js的基本應(yīng)用你知道多少

    Node.js的基本應(yīng)用你知道多少

    這篇文章主要為大家詳細(xì)介紹了Node.js的基本應(yīng)用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • Node.js?中使用fetch?按JSON格式發(fā)post請求的問題解析

    Node.js?中使用fetch?按JSON格式發(fā)post請求的問題解析

    最近在測試一個api,可以用curl命令直接訪問,指定header相關(guān)配置,request?body(JSON),成功后返回一個JSON,這篇文章主要介紹了Node.js?中使用fetch?按JSON格式發(fā)post請求,需要的朋友可以參考下
    2023-04-04
  • Node.js DES加密的簡單實現(xiàn)

    Node.js DES加密的簡單實現(xiàn)

    下面小編就為大家?guī)硪黄狽ode.js DES加密的簡單實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-07-07
  • 淺談Node.js:fs文件系統(tǒng)模塊

    淺談Node.js:fs文件系統(tǒng)模塊

    本篇文章主要介紹了Node.js:fs文件系統(tǒng)模塊,具有一定的參考價值,有需要的可以了解一下。
    2016-12-12
  • node.js讀取命令行參數(shù)詳解

    node.js讀取命令行參數(shù)詳解

    本文主要講解了node.js如何獲取命令行參數(shù),有需要的朋友可以參考下
    2022-10-10
  • Node.js使用Sharp.js進(jìn)行圖像處理的實踐與技巧

    Node.js使用Sharp.js進(jìn)行圖像處理的實踐與技巧

    Sharp.js 是一個高性能的 Node.js 圖像處理庫,基于 C 語言編寫的 libvips 庫封裝而來,提供了便捷、高效的圖片編輯與轉(zhuǎn)換功能,以下是對 Sharp.js 的深入解析,包括全方位實踐與技巧,需要的朋友可以參考下
    2024-08-08
  • 淺析node命令行交互原理

    淺析node命令行交互原理

    當(dāng)我們使用腳手架去創(chuàng)建一個項目的時候,通常會通過命令行交互來獲取一些信息,比如填項目名稱,選擇項目模板,選擇版本,我們雖然經(jīng)常用到,但是想必對于其中的原理還是不太了解,本文將待大家詳細(xì)介紹一下node命令行的交互原理,需要的朋友可以參考下
    2023-05-05
  • nodejs文件實現(xiàn)打包成exe, 并設(shè)置開機自啟動的方法詳解(沒有黑窗口)

    nodejs文件實現(xiàn)打包成exe, 并設(shè)置開機自啟動的方法詳解(沒有黑窗口)

    這篇文章主要介紹了nodejs文件實現(xiàn)打包成exe, 并設(shè)置開機自啟動的方法,結(jié)合實例形式分析了node.js使用pkg包實現(xiàn)生成exe可執(zhí)行文件的相關(guān)操作技巧,需要的朋友可以參考下
    2023-05-05
  • 在Node.js中實現(xiàn)視頻收藏功能

    在Node.js中實現(xiàn)視頻收藏功能

    在構(gòu)建視頻分享平臺時,視頻的收藏功能是用戶互動的重要組成部分,本文將介紹如何在Node.js應(yīng)用中實現(xiàn)視頻收藏功能,包括數(shù)據(jù)模型的創(chuàng)建、業(yè)務(wù)邏輯的實現(xiàn)以及接口的驗證測試,需要的朋友可以參考下
    2024-04-04
  • Node使用Nodemailer發(fā)送郵件的方法實現(xiàn)

    Node使用Nodemailer發(fā)送郵件的方法實現(xiàn)

    這篇文章主要介紹了Node使用Nodemailer發(fā)送郵件的方法實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02

最新評論

曲靖市| 威宁| 葵青区| 青川县| 青海省| 武安市| 两当县| 澄城县| 沅江市| 阳新县| 垦利县| 巫山县| 鲜城| 乌拉特前旗| 神农架林区| 濮阳市| 平山县| 象山县| 泰顺县| 集安市| 福建省| 宁波市| 繁昌县| 宣武区| 太仓市| 镶黄旗| 东平县| 宣汉县| 常州市| 丹凤县| 澄城县| 青田县| 隆德县| 南昌县| 门头沟区| 马公市| 于都县| 甘南县| 八宿县| 三门县| 昂仁县|