我们在使用koa2做路由拦截后一般都习惯于直接将查找对应处理函数的过程映射到项目的文件夹目录,如:

router.get('/test', app.controller.index.test);

app.controller.index.test 其实就是对应的处理函数,也就是 (ctx, next) => { },我们习惯于将app.controller.index.test映射到根目录下的  /controller/index/test.js ;或映射至 /controller/index.js,此时index.js的导出为一个对象,存在一个test的函数, 可以是:

{
test: async (ctx, next) => { }
}

实现这种类似的目录映射,一般有两种实现方式:

(1)初次controller加载器

(2)拦截时的按需controller加载器

两种方式各有利弊:

一、初次controller加载器

服务启动时依次遍历整个controller目录下的文件夹,并通过require动态绑定至对应的对象上。比较适合小型项目。

优点:只需要在服务启动时执行依次,后续无需再根据目录查找。

缺点:当项目文件量足够大时,重启服务的时间会变长,在宕机重启时,线上体验会有影响。

核心代码如下:

const path = require("path");
const fs = require('fs');
module.exports = function (opts) {
let {app,rules = []} = opts;
// 如果参数缺少实例 app,则抛出错误
if (!app) {
throw new Error("the app params is necessary!");
}
// 提取出 app 实例对象中的属性名
const appKeys = Object.keys(app);
rules.forEach((item) => {
let {folder,name} = item;
// 如果 app 实例中已经存在了传入过来的属性名,则抛出错误
if (appKeys.includes(name)) {
throw new Error(`the name of ${name} already exists on app!`);
}
let content = {};
//读取指定文件夹下(dir)的所有文件并遍历
fs.readdirSync(folder).forEach(filename => {
let extname = path.extname(filename); // 取出文件的后缀
if (extname === '.js') { // 只处理js文件
let name = path.basename(filename, extname); // 将文件名中去掉后缀
//读取文件中的内容并赋值绑定
content[name] = require(path.join(folder, filename));
}
});
app[name] = content; }) app.use(async (ctx, next) => {
rules.forEach((item, index) => {
let {name} = item;
if (Object.keys(ctx).indexOf(name) !== -1) {
throw new Error(`the name of ${name} already exists on ctx!`)
} else {
ctx[name] = app[name];
}
})
await next();
}) }
// 调用
miFileMap({
app,
rules: [{ //指定controller文件夹下的js文件,挂载在app.controller属性
folder: path.join(__dirname, '../controller'),
name: 'controller'
}
]
});

二、拦截时的按需controller加载器

在路由拦截时,根据当前路由寻找对应的文件模块,比较适合大型项目。

优点: 重启时间快,线上部署宕机重启时影响较小。

缺点: 每次的路由拦截时间后的寻找controller的时间会微微增长

在实现按需加载的时候,刚开始是面向过程的写法,会出现多次访问同一路由受影响的情况,所以以面向对象方式实现。

核心代码如下:

const path = require('path');
const fs = require('fs');
class DirProxy {
constructor (root) {
this.dir = [root];
} static getFile (baseDir) {
const baseFile = baseDir + '.js';
let targetDir = null,
targetFile = null;
try {
targetDir = fs.statSync(baseDir); } catch (err) {}
try {
targetFile = fs.statSync(baseFile);
} catch (err) {}
// console.log(baseDir, baseFile)
if (targetDir || targetFile) {
if (targetDir && targetDir.isDirectory()) {
return 'dir'
}
if (targetFile && targetFile.isFile()) {
return 'file'
}
return false;
} else {
return false;
}
} init () {
let _this = this;
let handler = {
get (target, key, receiver) {
console.log('dirproxy')
console.log(key)
// key可能会是Symbol(nodejs.util.inspect.custom)
if (key && Object.prototype.toString.call(key) === '[object String]') {
_this.dir.push(key)
}
// c:/FE/nodeFile/node_base_learn/ 为项目根目录
let baseDir = path.relative(__dirname, `c:/FE/nodeFile/node_base_learn/${_this.dir.join('/')}`);
let ctrPath = path.resolve(__dirname, baseDir)
let targetCtr = DirProxy.getFile(ctrPath);
if (targetCtr == 'dir') {
return new Proxy({path: _this.dir}, handler);
} else {
// 根据commonjs的模块解析规则可直接引入目录或js文件
return require(ctrPath)
}
},
set (target, key, value, receiver) {
return false;
},
construct: function(target, args) {
return false;
}
}
return new Proxy({path: _this.dir}, handler)
} }
module.exports = DirProxy

  

现在只是完成了get,set可根据自己需要定制。所有set直接返回false,即只读,也是可以的。

//调用方式
app.controller = new DirProxy('controller').init(); // 调用之后,便会以链式的方式逐级目录寻找js文件
app.controller.user.login

  

  

站在公司或项目长期发展的角度考虑问题的话,按需加载仍是相对稳妥的办法

koa2 定制开源框架github:https://github.com/pomelott/koa2_custom_optimize

框架持续更新中,喜欢请赐星。。。

【koa2基础框架封装】基于Proxy路由按需加载器和初始加载器的更多相关文章

  1. react-router 4.x 路由按需加载

    react-router 4 代码分割(按需加载) 官方文档  https://serverless-stack.com/chapters/code-splitting-in-create-react ...

  2. react16 路由按需加载、路由权限配置

    1. 路由按需加载: 不做按需加载,代码全部打包在bundle.js 文件里,首屏渲染很慢,项目文件较多,会出现1分钟加载的可能性. import React, { Component } from ...

  3. vue中路由按需加载的几种方式

    使用vue-cli构建项目后,我们会在Router文件夹下面的index.js里面引入相关的路由组件,如: import Hello from '@/components/Hello' import ...

  4. vue 动态路由按需加载的三种方式

    在Vue项目中,一般使用vue-cli构建项目后,我们会在Router文件夹下面的index.js里面引入相关的路由组件,如: import Hello from '@/components/Hell ...

  5. react路由按需加载方法

    使用router4之后以前的按需加载方法require.ensure 是不好使了. 所以我们改用react-loadable插件做按需加载. 第一步: yarn add react-loadable ...

  6. vue项目实现路由按需加载的3种方式

    vue异步组件技术 ==== 异步加载vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件 /* vue异步组件技术 */ { ...

  7. vue学习指南:第十二篇(详细) - Vue的 路由 第二篇 ( 路由按需加载(懒加载))

    各位朋友 因 最近工作繁忙,小编停更了一段时间,快过年了,小编祝愿 大家 事业有成 学业有成 快乐健康 2020开心过好每一天.从今天开始 我会抽时间把 Vue 的知识点补充完整,以及后期会带给大家更 ...

  8. react 实现路由按需加载

    import() 方法: async.js 文件内容: import React from 'react'; // import "babel-polyfill"; //compo ...

  9. Google官方网络框架-Volley的使用解析Json以及加载网络图片方法

    Google官方网络框架-Volley的使用解析Json以及加载网络图片方法 Volley是什么? Google I/O 大会上,Google 推出 Volley的一个网络框架 Volley适合什么场 ...

随机推荐

  1. python 教程 第六章、 模块

    第六章. 模块 1) 模块 sys模块 字节编译的.pyc文件,优化编译后生成pyo文件 2) from..import语句 import sys print 'The command line ar ...

  2. WPF 3D 平移模型+动画(桥梁检测系统)

    原文:WPF 3D 平移模型+动画(桥梁检测系统) 关于WPF 3D,网上有很多旋转的例子,但是关于平移的例子并不是太多.本文并非WPF 3D扫盲篇,因此需要对WPF 3D有一定了解,至少知道View ...

  3. WPF 将Bitmapsource转换到Emgu.cv.image

    原文:WPF 将Bitmapsource转换到Emgu.cv.image Transform WPF BitmapSource to Emgu.CV.Image******* /// <summ ...

  4. C++异常机制的实现方式和开销分析 (大图,编译器会为每个函数增加EHDL结构,组成一个单向链表,非常著名的“内存访问违例”出错对话框就是该机制的一种体现)

    白杨 http://baiy.cn 在我几年前开始写<C++编码规范与指导>一文时,就已经规划着要加入这样一篇讨论 C++ 异常机制的文章了.没想到时隔几年以后才有机会把这个尾巴补完 :- ...

  5. Linux 下蓝牙bluez分析及使用 (1)

    蓝牙耳机的使用 由于Linux下蓝牙使用不及Windows下直观,致使使用时会出现一些小问题.虽然是小问题,但是由于普通的操作都具有顺序性,前面的中断了,后面的哪怕再简单,也无法继续了.正好近期工作与 ...

  6. 在DELPHI中*.wav 文件怎么加到资源文件中

    比较“流行”的说法是:“16位的Delphi   1.0和32位的Delphi2.0.3.0都提供了资源         编译工具,其中   Delphi   1.0的资源编译器叫BRCC.EXE,D ...

  7. 零元学Expression Blend 4 - Chapter 35 讨厌!!我不想一直重复设定!!『Template Binding』使用前後的差异

    原文:零元学Expression Blend 4 - Chapter 35 讨厌!!我不想一直重复设定!!『Template Binding』使用前後的差异 因为先前写到自制Button时需特别注意T ...

  8. Android零基础入门第60节:日历视图CalendarView和定时器Chronometer

    原文:Android零基础入门第60节:日历视图CalendarView和定时器Chronometer 上一期学习了AnalogClock.DigitalClock和TextClock时钟组件,本期继 ...

  9. DBShop 电子商务网店系统

    DBShop 电子商务网店系统,采用业界知名框架 ZendFramework 2 开发而成. 下面为功能简介 1.在线更新:在线系统更新和在线模板安装与更新,简单.方便.快捷,省却了手动更新的繁琐步骤 ...

  10. 机器学习Machine Learning(ML)

    什么是机器学习 定义 对于某个任务T和表现的衡量P,当计算机程序在该任务T的表现上,经过P的衡量,随着经验E而增长,称计算机能够通过经验E来学习该任务.(Tom Mitchell) 举例而言,在跳棋游 ...