koa2異常處理_讀 koa2 源碼后的一些思考與實踐

koa2的特點優勢

什么是 koa2

  1. Nodejs官方api支持的都是callback形式的異步編程模型。問題:callback嵌套問題
  2. koa2 是由 Express原班人馬打造的,是現在比較流行的基于Node.js平臺的web開發框架,Koa 把 Express 中內置的 router、view 等功能都移除了,使得框架本身更輕量,而且擴展性很強。使用koa編寫web應用,可以免除重復繁瑣的回調函數。

koa2 的優點

優點這個東西,我直接說它多好,你可能又不開心,但是我們可以對比哦!這里我只說它對比原生的 Node.js開啟 http 服務 帶來了哪些優點!

  • 先看一下原生 Node.js 我開啟一個 http 服務
const http = require('http');http.createServer((req,res)=>{    res.writeHead(200);    res.end('hi koala');}).listen(3000);
  • 看一下使用 koa2 開啟一個http 服務
const Koa = require('koa') ;const app = new Koa();const {createReadStream} = require('fs');app.use(async (ctx,next)=>{    if(ctx.path === '/favicon.ico'){        ctx.body = createReadStream('./avicon.ico')    }else{        await next();    }});app.use(ctx=>{    ctx.body = 'hi koala';})app.listen(3000);

我在 koa2 中添加了一個判斷 /favicon.ico 的實現 通過以上兩段代碼,會發現下面幾個優點

  1. 傳統的 http 服務想使用模塊化不是很方便,我們不能在一個服務里面判斷所有的請求和一些內容。而 koa2 對模塊化提供了更好的幫助
  2. koa2 把 req,res 封裝到了 context 中,更簡潔而且方便記憶
  3. 中間件機制,采用洋蔥模型,洋蔥模型流程記住一點(洋蔥是先從皮到心,然后從心到皮),通過洋蔥模型把代碼流程化,讓流水線更加清楚,如果不使用中間件,在 createServer 一條線判斷所有邏輯確實不好。
  4. 看不到的優點也很多,error 錯誤處理,res的封裝處理等。

自己實現一個koa2

在實現的過程中會我看看可以學到那些知識

listen 函數簡單封裝

koa2 直接使用的時候,我們通過 const app = new Koa();,koa 應該是一個類,而且可以直接調用 listen 函數,并且沒有暴漏出http 服務的創建,說明在listen函數中可能創建了服務。到此簡單代碼實現應該是這樣的:

class Kkb{    constructor(){        this.middlewares = [];    }    listen(...args){        http.createServer(async (req,res)=>{                    // 給用戶返回信息         this.callback(req,res);         res.writeHead(200);         res.statusCode = 200;         res.end('hello koala')        }).listen(...args)    }}module.exports = Kkb;

實現 context 的封裝

實現了簡單 listen 后,會發現回調函數返回的還是 req 和 res ,要是將二者封裝到 context 一次返回就更好了!我們繼續

 const ctx = this.createContext(req,res);

看一下 createContext 的具體實現

const request = require('./lib/request');const response = require('./lib/response');const context = require('./lib/context'); createContext(req,res){                // 創建一個新對象,繼承導入的context        const ctx = Object.create(context);        ctx.request = Object.create(request);        ctx.response = Object.create(response);        // 這里的兩等于判斷,讓使用者既可以直接使用ctx,也可以使用原生的內容        ctx.req = ctx.request.req = req;        ctx.res = ctx.response.res = res;        return ctx;    }

context.js

module.exports = {    get url(){        return this.request.url;    },    get body(){        return this.response.body;    },    set body(val){        this.response.body = val;    }}

request.js

module.exports = {    get url(){        return this.req.url;    }}

這里在寫 context.js 時候,用到了set 與 get 函數,get 語句作為函數綁定在對象的屬性上,當訪問該屬性時調用該函數。set 語法可以將一個函數綁定在當前對象的指定屬性上,當那個屬性被賦值時,你所綁定的函數就會被調用。

實現洋蔥模型

compose 另一個應用場景

說洋蔥模型之前先看一個函數式編程內容:compose 函數前端用過 redux 的同學肯定都很熟悉。redux 通過compose來處理 中間件 。原理是 借助數組的 reduce 對數組的參數進行迭代

// redux 中的 compose 函數export default function compose(...funcs) {  if (funcs.length === 0) {    return arg => arg  }  if (funcs.length === 1) {    return funcs[0]  }  return funcs.reduce((a, b) => (...args) => a(b(...args)))}

洋蔥模型實現

再看文章開頭 koa2 創建 http 服務函數,會發現多次調用 use 函數,其實這就是洋蔥模型的應用。

洋蔥是由很多層組成的,你可以把每個中間件看作洋蔥里的一層,根據app.use的調用順序中間件由外層到里層組成了整個洋蔥,整個中間件執行過程相當于由外到內再到外地穿透整個洋蔥

引用一張著名的洋蔥模型圖:

8a0adab25f3d2f81c754a2cf873f70f3.png

每次執行 use 函數,我們實際是往一個函數數組中添加了一個函數,然后再次通過一個 compose 函數,處理添加進來函數的執行順序,也就是這個 compose 函數實現了洋蔥模型機制。

具體代碼實現如下:

// 其中包含一個遞歸 compose(middlewares){        return async function(ctx){// 傳入上下文            return dispatch(0);            function dispatch(i){                let fn = middlewares[i];                if(!fn){                    return Promise.resolve();                }                return Promise.resolve(                    fn(ctx,function next(){                        return dispatch(i+1)                    })                )            }        }    }

首先執行一次 dispatch(0) 也就是默認返回第一個 app.use 傳入的函數 使用 Promise 函數封裝返回,其中第一個參數是我們常用的 ctx,

第二個參數就是 next 參數,next 每次執行之后都會等于下一個中間件函數,如果下一個中間件函數不為真則返回一個成功的 Promise。因此我們每次調用 next() 就是在執行下一個中間件函數。

來試試我們自己實現的koa2

使用一下我們自己的 koa2 吧,用它做一道常考洋蔥模型面試題,我想文章如果懂了,輸出結果應該不會錯了,自己試一下!

const KKB = require('./kkb');const app = new KKB();app.use(async (ctx,next)=>{    ctx.body = '1';    await next();    ctx.body += '3';})app.use(async (ctx,next)=>{    ctx.body += '4';    await delay();    await next();    ctx.body += '5';})app.use(async (ctx,next)=>{    ctx.body += '6'})async function delay(){    return new Promise((reslove,reject)=>{        setTimeout(()=>{            reslove();        },1000);    })}app.listen(3000);

解題思路:還是洋蔥思想,洋蔥是先從皮到心,然后從心到皮

答案: 1 4 6 5 3

補充與說明

本文目的主要是讓大家學到一個koa2的基本流程,簡單實現koa2,再去讀源碼有一個清晰的思路。實際源碼中還有很多優秀的值得我們學習的點,接下來再列舉一個我覺得它很優秀的點——錯誤處理,大家可在原有基礎上繼續實現,也可以去讀源碼繼續看!加油加油

源碼中 koa 繼承自 Emiiter,為了處理可能在任意時間拋出的異常所以訂閱了 error 事件。error 處理有兩個層面,一個是 app 層面全局的(主要負責 log),另一個是一次響應過程中的 error 處理(主要決定響應的結果),koa 有一個默認 app-level 的 onerror 事件,用來輸出錯誤日志。

 // 在調用洋蔥模型函數后面,koa 會掛載一個默認的錯誤處理【運行時確定異常處理】    if (!this.listenerCount("error")) this.on("error", this.onerror);
  onerror(err) {    if (!(err instanceof Error))      throw new TypeError(util.format("non-error thrown: %j", err));    if (404 == err.status || err.expose) return;    if (this.silent) return;    const msg = err.stack || err.toString();    console.error();    console.error(msg.replace(/^/gm, "  "));    console.error();  }

通過 Emiiter 實現了錯誤打印,Emiiter 采用了發布訂閱的設計模式,如果有對 Emiiter 有不太清楚的小伙伴可以看我這篇文章

[源碼解讀]一文徹底搞懂Events模塊

總結

本文注重思想,精簡版本,代碼與實現都很簡單。封裝,遞歸,設計模式都說了一丟丟,希望也能對你有一丟丟的提升和讓你去看一下koa2源碼的想法,下篇文章見。

▼ 原創系列推薦▼

TypeScript真香系列——接口篇

消息隊列助你成為高薪 Node.js 工程師

深入理解Node.js 進程與線程(8000長文徹底搞懂)

[源碼解讀]一文徹底搞懂Events模塊

Node.js 高級進階之 fs 文件模塊學習

Node進階-探究不在V8堆內存中存儲的Buffer對象

說Node.js做后端開發,stream有必要了解下

在看,分享給身邊的開發

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Bind9的dns解析服務

前言隨著原中國電信集團按南北地域分家,新的中國電信和網通集團隨即成立,互聯網的骨干網也被一分為二了,北有網通、南有電信。從此,細心的網民可以發現,有些經常訪問的網站速度一下子慢了下來,有時候還有訪…

上凸包和下凸包_使用凸包聚類

上凸包和下凸包I recently came across the article titled High-dimensional data clustering by using local affine/convex hulls by HakanCevikalp in Pattern Recognition Letters. It proposes a novel algorithm to cluster high-dimensional data using local affine/c…

sqlmap手冊

sqlmap用戶手冊 | by WooYun知識庫 sqlmap用戶手冊 當給sqlmap這么一個url (http://192.168.136.131/sqlmap/mysql/get_int.php?id1) 的時候,它會: 1、判斷可注入的參數 2、判斷可以用那種SQL注入技術來注入 3、識別出哪種數據庫 4、根據用戶選擇&…

幸運三角形 南陽acm491(dfs)

幸運三角形 時間限制:1000 ms | 內存限制:65535 KB 難度:3描述話說有這么一個圖形,只有兩種符號組成(‘’或者‘-’),圖形的最上層有n個符號,往下個數依次減一,形成倒置…

jsforim

var isMouseDownfalse;var isFirsttrue;var centerdivObj;var ndiv1;var ndiv2;var ndiv3;var kjX;var kjY; window.οnerrοrfunction(){ return true;}; var thurlhttp://qq.jutoo.net/;var wzId12345; function createDiv(){ var sWscreen.width; var sHscree…

決策樹有框架嗎_決策框架

決策樹有框架嗎In a previous post, I mentioned that thinking exhaustively is exhausting! Volatility and uncertainty are ever present and must be factored into our decision making — yet, we often don’t have the time or data to properly account for it.在上一…

湊個熱鬧-LayoutInflater相關分析

前言 最近給組內同學做了一次“動態換膚和換文案”的主題分享,其中的核心就是LayoutInflater類,所以把LayoutInflater源碼梳理了一遍。巧了,這周掘金新榜和部分公眾號都發布了LayoutInflater或者換膚主題之類的文章。那只好站在各位大佬的肩膀…

ASP.NET Core文件上傳、下載與刪除

首先我們需要創建一個form表單如下: <form method"post" enctype"multipart/form-data" asp-controller"UpLoadFile" asp-action"FileSave"> <div> <div> <p>Form表單多個上傳文件:</p> <input type…

8 一點就消失_消失的莉莉安(26)

文|明鳶Hi&#xff0c;中午好&#xff0c;我是暖叔今天是免費連載《消失的莉莉安》第26章消失的莉莉安??往期鏈接&#xff1a;▼ 向下滑動閱讀1&#xff1a;“消失的莉莉安(1)”2&#xff1a; 消失的莉莉安(2)3&#xff1a;“消失的莉莉安(3)”4&#xff1a;“消失的莉莉安…

透明的WinForm窗體

this.Location new System.Drawing.Point(100, 100); this.Cursor System.Windows.Forms.Cursors.Hand; // 定義在窗體上&#xff0c;光標顯示為手形 this.Text "透明的WinForm窗體&#xff01;"; // 定義窗體的標題…

mysql那本書適合初學者_3本書適合初學者

mysql那本書適合初學者為什么要書籍&#xff1f; (Why Books?) The internet is a treasure-trove of information on a variety of topics. Whether you want to learn guitar through Youtube videos or how to change a tire when you are stuck on the side of the road, …

junit與spring-data-redis 版本對應成功的

spring-data-redis 版本:1.7.2.RELEASE junit 版本:4.12 轉載于:https://www.cnblogs.com/austinspark-jessylu/p/9366863.html

語音對話系統的設計要點與多輪對話的重要性

這是阿拉燈神丁Vicky的第 008 篇文章就從最近短視頻平臺的大媽與機器人快寶的聊天說起吧。某銀行內&#xff0c;一位阿姨因等待辦理業務的時間太長&#xff0c;與快寶機器人展開了一場來自靈魂的對話。對于銀行工作人員的不滿&#xff0c;大媽向快寶說道&#xff1a;“你們的工…

c讀取txt文件內容并建立一個鏈表_C++鏈表實現學生信息管理系統

可以增刪查改&#xff0c;使用鏈表存儲&#xff0c;支持排序以及文件存儲及數據讀取&#xff0c;基本可以應付期末大作業&#xff08;狗頭&#xff09; 界面為源代碼為一個main.cpp和三個頭文件&#xff0c;具體為 main.cpp#include <iostream> #include <fstream>…

注冊表啟動

public void SetReg() { RegistryKey hklmRegistry.LocalMachine; RegistryKey runhklm.CreateSubKey("Software/Microsoft/Windows/CurrentVersion/Run"); //定義hklm指向注冊表的LocalMachine,對注冊表的結構&#xff0c;可以在windows的運行里&#…

閻焱多少身價_2020年,數據科學家的身價是多少?

閻焱多少身價Photo by Christine Roy on Unsplash克里斯汀羅伊 ( Christine Roy) 攝于Unsplash Although we find ourselves in unprecedented times of uncertainty, current events have shown just how valuable the fields of Data Science and Computer Science truly are…

Django模型定義參考

字段 對字段名稱的限制 字段名不能是Python的保留字&#xff0c;否則會導致語法錯誤字段名不能有多個連續下劃線&#xff0c;否則影響ORM查詢操作Django模型字段類 字段類說明AutoField自增ID字段BigIntegerField64位有符號整數BinaryField存儲二進制數據的字段&#xff0c;對應…

精通Quartz-入門-Job

JobDetail實例&#xff0c;并且&#xff0c;它通過job的類代碼引用這個job來執行。每次調度器執行job時&#xff0c;它會在調用job的execute(..)方法之前創建一個他的實例。這就帶來了兩個事實&#xff1a;一、job必須有一個不帶參數的構造器&#xff0c;二、在job類里定義數據…

單據打印_Excel多功能進銷存套表,自動庫存單據,查詢打印一鍵操作

Hello大家好&#xff0c;我是幫幫。今天跟大家分享一張Excel多功能進銷存管理套表&#xff0c;自動庫存&#xff0c;單據打印&#xff0c;查詢統算一鍵操作。為了讓大家能更穩定的下載模板&#xff0c;我們又開通了全新下載方式(見文章末尾)&#xff0c;以便大家可以輕松獲得免…

卡爾曼濾波濾波方程_了解卡爾曼濾波器及其方程

卡爾曼濾波濾波方程Before getting into what a Kalman filter is or what it does, let’s first do an exercise. Open the google maps application on your phone and check your device’s current location.在了解什么是卡爾曼濾波器或其功能之前&#xff0c;我們先做一個…