变压器厂家简介 从一个优质开源项目来望前端架构

栏目分类
变压器厂家简介

你的位置:电竞菠菜分析 > 变压器厂家简介 > 变压器厂家简介 从一个优质开源项目来望前端架构

变压器厂家简介 从一个优质开源项目来望前端架构

发布日期:2021-07-08 17:56    点击次数:212

 

何为体系架构师?

体系架构师是一个最后确认和评估体系需求,给出开发规范,搭建体系实现的核心构架,并清亮技术细节、扫清主要难点的技术人员。主要着眼于体系的“技术实现”。因此他/她答该是特定的开发平台、说话、工具的行家,对常见行使场景能给出最正当的解决方案,同时要对所属的开发团队有有余的晓畅,能够评估本身的团队实现特定的功能需求必要的代价。体系架构师负责设计体系集体架构,从需求到设计的每个细节都要考虑到,把握整个项目,使设计的项目尽量效果高,开发容易,维护方便,升级浅易等

这是百度百科的答案

大无数人的题目 如何成为别名前端架构师? 其实,前端架构师不该该是一个头衔,而答该是一个过程。吾记得掘金上有人写过一篇文章: 《吾在一个幼公司,吾把吾们公司前端给架构了》 , (吾那时还望成 《吾把吾们公司架构师给上了》 ) 吾面试过许多人,从幼公司出来(吾也是从一个很幼很幼的公司出来,现在也没在什么 BATJ ),最大的题目在于,觉得本身不是 leader ,就异国想过如何去升迁、优化项目,而是去钻研一些花里胡哨的东西,却异国真实行使在项目中。(自然很少会有深度) 在一个两至三人的前端团队幼公司,你去赓续优化、升迁项目体验,更新迭代替换技术栈,那么你就是 前端架构师 正式最先 吾们从一个比较不错的项眼前手,谈谈一个前端架构师要做什么 SpaceX-API SpaceX-API 是什么? SpaceX-API 是一个用于火箭、核心舱、太空舱、发射台和发射数据的开源 REST API(并且是行使Node.js编写,吾们用这个项目借鉴无可厚非)

为了浏览的安详度,吾把下面的正文尽量口语化一点

先把代码搞下来
git clone https://github.com/r-spacex/SpaceX-API.git 
一个特出的开源项目搞下来以后,怎么分析它?大片面时候,你答该先望它的目录组织以及倚赖的第三方库( package.json 文件)

找到 package.json 文件的几个关键点:

main 字段(项目入口) scripts 字段(实走命令脚本) dependencies和devDependencies字段(项方针倚赖,区分线上倚赖和开发倚赖,吾本人是专门望中这个点,SpaceX-API也相符吾的不益看念,厉格的区分倚赖根据)
"main": "server.js",    "scripts": {     "test": "npm run lint && npm run check-dependencies && jest --silent --verbose",     "start": "node server.js",     "worker": "node jobs/worker.js",     "lint": "eslint .",     "check-dependencies": "npx depcheck --ignores=\"pino-pretty\""   }, 
议决上面能够望到,项目入口为 server.js 项目启动命令为 npm run start

几个主要的倚赖:

"koa": "^2.13.0",     "koa-bodyparser": "^4.3.0",     "koa-conditional-get": "^3.0.0",     "koa-etag": "^4.0.0",     "koa-helmet": "^6.0.0",     "koa-pino-logger": "^3.0.0",     "koa-router": "^10.0.0",     "koa2-cors": "^2.0.6",     "lodash": "^4.17.20",     "moment-range": "^4.0.2",     "moment-timezone": "^0.5.32",     "mongoose": "^5.11.8",     "mongoose-id": "^0.1.3",     "mongoose-paginate-v2": "^1.3.12",     "eslint": "^7.16.0",     "eslint-config-airbnb-base": "^14.2.1",     "eslint-plugin-import": "^2.22.1",     "eslint-plugin-jest": "^24.1.3",     "eslint-plugin-mongodb": "^1.0.0",     "eslint-plugin-no-secrets": "^0.6.8",     "eslint-plugin-security": "^1.4.0",     "jest": "^26.6.3",     "pino-pretty": "^4.3.0" 

都是一些通用主流库: 主要是koa框架,以及一些koa的一些中间件,monggose(连接行使mongoDB),eslint(代码质量检查)

这边强调一点,倘若你的代码必要两人及以上维护,吾就剧烈提出你不要行使任何暗魔法,以及不行使非主流的库,除非你编写核心底层逻辑时候非用不能(这个时候答该只有你维护)

项目目录

这是一套标准的 REST API, 厉格分层

几个重点目录 :

server.js 项目入口

app.js 入口文件

services 文件夹 => 项目挑供服务层

scripts 文件夹 => 项目脚本

middleware 文件夹 => 中间件

docs 文件夹 =>文档存放

tests 文件夹 => 单元测试代码存放

.dockerignore docker的无视文件变压器厂家简介

Dockerfile 实走docker build命令读取配置的文件

.eslintrc eslint配置文件

jobs 文件夹 => 吾想答该是对答检查他们api服务的代码,内里都是准备的一些参数然后直接调服务

逐个分析 从项目倚赖安置说首

安置环境厉格区睁开发倚赖和线上倚赖,让浏览代码者一目了然哪些倚赖是线上必要的

"dependencies": {     "blake3": "^2.1.4",     "cheerio": "^1.0.0-rc.3",     "cron": "^1.8.2",     "fuzzball": "^1.3.0",     "got": "^11.8.1",     "ioredis": "^4.19.4",     "koa": "^2.13.0",     "koa-bodyparser": "^4.3.0",     "koa-conditional-get": "^3.0.0",     "koa-etag": "^4.0.0",     "koa-helmet": "^6.0.0",     "koa-pino-logger": "^3.0.0",     "koa-router": "^10.0.0",     "koa2-cors": "^2.0.6",     "lodash": "^4.17.20",     "moment-range": "^4.0.2",     "moment-timezone": "^0.5.32",     "mongoose": "^5.11.8",     "mongoose-id": "^0.1.3",     "mongoose-paginate-v2": "^1.3.12",     "pino": "^6.8.0",     "tle.js": "^4.2.8",     "tough-cookie": "^4.0.0"   },   "devDependencies": {     "eslint": "^7.16.0",     "eslint-config-airbnb-base": "^14.2.1",     "eslint-plugin-import": "^2.22.1",     "eslint-plugin-jest": "^24.1.3",     "eslint-plugin-mongodb": "^1.0.0",     "eslint-plugin-no-secrets": "^0.6.8",     "eslint-plugin-security": "^1.4.0",     "jest": "^26.6.3",     "pino-pretty": "^4.3.0"   }, 

项目目录划分

目录划分,厉格分层

通用,清亮简介清新,让人一望就懂

正式最先望代码 入口文件, server.js 最先
const http = require('http'); const mongoose = require('mongoose'); const { logger } = require('./middleware/logger'); const app = require('./app');  const PORT = process.env.PORT || 6673; const SERVER = http.createServer(app.callback());  // Gracefully close Mongo connection const gracefulShutdown = () => {   mongoose.connection.close(false, () => {     logger.info('Mongo closed');     SERVER.close(() => {       logger.info('Shutting down...');       process.exit();     });   }); };  // Server start SERVER.listen(PORT, '0.0.0.0', () => {   logger.info(`Running on port: ${PORT}`);    // Handle kill commands   process.on('SIGTERM', gracefulShutdown);    // Prevent dirty exit on code-fault crashes:   process.on('uncaughtException', gracefulShutdown);    // Prevent promise rejection exits   process.on('unhandledRejection', gracefulShutdown); }); 

几个特出的地方

每个回调函数都会有声明功能注解

像 SERVER.listen 的host参数也会传入,这边是为了避免产生不消要的麻烦。至于这个麻烦,吾这就不注释了(必定要有能望到的默认值,而不是去靠猜) 对于监听端口启动服务以后一些变态同一捕获,并且同一日志记录, process 进程退出,防止展现僵物化线程、端口占用等(由于node安放时候能够会用pm2等手段,在 Worker 线程中,process.exit()将停留现在面程而不是当进取程) app.js入口文件 这边是由 koa 挑供基础服务 monggose 负责连接 mongoDB 数据库

若干中间件负责跨域、日志、舛讹、数据处理等变压器厂家简介

const conditional = require('koa-conditional-get'); const etag = require('koa-etag'); const cors = require('koa2-cors'); const helmet = require('koa-helmet'); const Koa = require('koa'); const bodyParser = require('koa-bodyparser'); const mongoose = require('mongoose'); const { requestLogger, logger } = require('./middleware/logger'); const { responseTime, errors } = require('./middleware'); const { v4 } = require('./services');  const app = new Koa();  mongoose.connect(process.env.SPACEX_MONGO, {   useFindAndModify: false,   useNewUrlParser: true,   useUnifiedTopology: true,   useCreateIndex: true, });  const db = mongoose.connection;  db.on('error', (err) => {   logger.error(err); }); db.once('connected', () => {   logger.info('Mongo connected');   app.emit('ready'); }); db.on('reconnected', () => {   logger.info('Mongo re-connected'); }); db.on('disconnected', () => {   logger.info('Mongo disconnected'); });  // disable console.errors for pino app.silent = true;  // Error handler app.use(errors);  app.use(conditional());  app.use(etag());  app.use(bodyParser());  // HTTP header security app.use(helmet());  // Enable CORS for all routes app.use(cors({   origin: '*',   allowMethods: ['GET', 'POST', 'PATCH', 'DELETE'],   allowHeaders: ['Content-Type', 'Accept'],   exposeHeaders: ['spacex-api-cache', 'spacex-api-response-time'], }));  // Set header with API response time app.use(responseTime);  // Request logging app.use(requestLogger);  // V4 routes app.use(v4.routes());  module.exports = app; 
逻辑清亮,自上而下,最先连接db数据库,挂载各栽事件后,经由koa各栽中间件,而后真实行使koa路由挑供api服务(代码编写挨次,即代码运走后的营业逻辑,吾们写前端的react等的时候,也挑倡由生命周期运走挨次去编写组件代码,而不是先编写unmount生命周期,再编写mount),例如答该云云:
//组件挂载 componentDidmount(){  } //组件必要更新时 shouldComponentUpdate(){  } //组件将要卸载 componentWillUnmount(){  } ... render(){} 
router的代码,简介清新
const Router = require('koa-router'); const admin = require('./admin/routes'); const capsules = require('./capsules/routes'); const cores = require('./cores/routes'); const crew = require('./crew/routes'); const dragons = require('./dragons/routes'); const landpads = require('./landpads/routes'); const launches = require('./launches/routes'); const launchpads = require('./launchpads/routes'); const payloads = require('./payloads/routes'); const rockets = require('./rockets/routes'); const ships = require('./ships/routes'); const users = require('./users/routes'); const company = require('./company/routes'); const roadster = require('./roadster/routes'); const starlink = require('./starlink/routes'); const history = require('./history/routes'); const fairings = require('./fairings/routes');  const v4 = new Router({   prefix: '/v4', });  v4.use(admin.routes()); v4.use(capsules.routes()); v4.use(cores.routes()); v4.use(crew.routes()); v4.use(dragons.routes()); v4.use(landpads.routes()); v4.use(launches.routes()); v4.use(launchpads.routes()); v4.use(payloads.routes()); v4.use(rockets.routes()); v4.use(ships.routes()); v4.use(users.routes()); v4.use(company.routes()); v4.use(roadster.routes()); v4.use(starlink.routes()); v4.use(history.routes()); v4.use(fairings.routes());  module.exports = v4; 
模块多多,找几个代外性的模块 admin 模块
const Router = require('koa-router'); const { auth, authz, cache } = require('../../../middleware');  const router = new Router({   prefix: '/admin', });  // Clear redis cache router.delete('/cache', auth, authz('cache:clear'), async (ctx) => {   try {     await cache.redis.flushall();     ctx.status = 200;   } catch (error) {     ctx.throw(400, error.message);   } });  // Healthcheck router.get('/health', async (ctx) => {   ctx.status = 200; });  module.exports = router; 

分析代码

 这是一套标准的restful API ,挑供的/admin/cache接口,乞求手段为delete,乞求这个接口,最先要经过auth和authz两个中间件处理 这边增添一个幼细节 一个用户访问一套体系,有两栽状态,未登陆和已登陆,倘若你未登陆去实走一些操作,后端答该返回 401 。但是登录后,你只能做你权限内的事情,例如你只是一个打工人,你说你要关闭这个公司,那么对不首,你的状态码此时答该是 403 回到admin 现在的你,想要清空这个缓存,调用/admin/cache接口,那么最先要经过 auth 中间件判定你是否有登录
/**  * Authentication middleware  */ module.exports = async (ctx, next) => {   const key = ctx.request.headers['spacex-key'];   if (key) {     const user = await db.collection('users').findOne({ key });     if (user?.key === key) {       ctx.state.roles = user.roles;       await next();       return;     }   }   ctx.status = 401;   ctx.body = 'https://youtu.be/RfiQYRn7fBg'; }; 
倘若异国登录过,那么意味着你异国权限,此时为401状态码,你答该去登录.倘若登录过,那么答该前去下一个中间件 authz 。 (以是redux的中间件源码是多么主要。它能够说贯穿了吾们整个前端生涯,吾以前些过它的分析,兴味味的能够翻一翻公多号)
/**  * Authorization middleware  *  * @param   {String}   role   Role for protected route  * @returns {void}  */ module.exports = (role) => async (ctx, next) => {   const { roles } = ctx.state;   const allowed = roles.includes(role);   if (allowed) {     await next();     return;   }   ctx.status = 403; }; 
 在authz这边会根据你传入的操作类型(这边是'cache:clear'),望你的对答一切权限roles内里是否包含传入的操作类型role 。倘若异国,就返回403,倘若有,就赓续下一个中间件 - 即真实的/admin/cache接口
// Clear redis cache router.delete('/cache', auth, authz('cache:clear'), async (ctx) => {   try {     await cache.redis.flushall();     ctx.status = 200;   } catch (error) {     ctx.throw(400, error.message);   } }); 
此时现在,行使try catch包裹逻辑代码,当redis消弭一切缓存成功即会返回状态码400,倘若报错,就会抛出舛讹码和因为。接由洋葱圈外层的 error 中间件处理
/**  * Error handler middleware  *  * @param   {Object}    ctx       Koa context  * @param   {function}  next      Koa next function  * @returns {void}  */ module.exports = async (ctx, next) => {   try {     await next();   } catch (err) {     if (err?.kind === 'ObjectId') {       err.status = 404;     } else {       ctx.status = err.status || 500;       ctx.body = err.message;     }   } }; 
云云只要肆意的 server 层内部展现变态,只要抛出,就会被 error 中间件处理,直接返回状态码和舛讹新闻. 倘若异国传入状态码,那么默认是500(以是吾之前说过,代码要安详,必定要有表现的指定默认值,要关注代码变态的逻辑,例如前端setLoading,乞求战败也要作废loading,不然用户就没法重试了,有能够这一瞬休只是用户网络出错呢)

补一张koa洋葱圈的图

再接下来望其他的services

现在,都专门轻盈就能理解了

// Get one history event router.get('/:id', cache(300), async (ctx) => {   const result = await History.findById(ctx.params.id);   if (!result) {     ctx.throw(404);   }   ctx.status = 200;   ctx.body = result; });  // Query history events router.post('/query', cache(300), async (ctx) => {   const { query = {}, options = {} } = ctx.request.body;   try {     const result = await History.paginate(query, options);     ctx.status = 200;     ctx.body = result;   } catch (error) {     ctx.throw(400, error.message);   } }); 

议决这个项目,吾们能学到什么

一个能上天的项目,必然是专门安详、高可用的,吾们最先要学习它的特出点:用最浅易的技术添上最浅易的实现手段,让人一眼就能望懂它的代码和分层

再者:简洁的注解是必要的

从营业角度去抽象公共层,例如鉴权、舛讹处理、日志等为公共模块(中间件,前端能够是一个工具函数或组件)

多考虑舛讹变态的处理,前端也是如此,js大多舛讹发生来源于a.b.c这栽代码(倘若a.b为undefined那么就会报错了)

表现的指定默认值,不让代码浏览者去推想

目录分区必定要简洁清新,分层清亮,易于维护和拓展

成为一个特出前端架构师的几个技能点

原生JavaScript、CSS、HTML基础壮实(体系学习过)

原生Node.js基础壮实(体系学习过),Node.js不光挑供服务,更多的是用于制作工具,以及现在serverless场景也会用到,还有SSR

熟识框架和类库原理,能手写浅易的常用类库,例如promise redux 等

数据组织基础壮实,晓畅常用、常见算法

linux基础壮实(做工具,搭环境,编写构建脚本等有会用到)

熟识TCP和http等通信制定

熟识操作体系linux Mac windows iOS 安卓等(在跨平台产品时候会遇到)

会行使docker(安放有关)

会一些c++最佳(在addon场景等,再者Node.js和JavaScript内心上是基于 C++ )

懂基本数据库、redis、nginxs操作,像跨平台产品,基本前端都会有个sqlite之类的,像倘若是node自身挑供服务,数据库和redis清淡少不了

再者是要多浏览特出的开源项目源码,不消太多,但是必定要精

【编辑选举】变压器厂家简介

100W并发秒杀体系架构 有了这个开源项目,不会 Web 开发也能让数据“动”首来! 90% 前端都会的 ES6 简化代码技巧,你用过哪些? 一份完善的亿级新闻中间架构方案! Docker+kubernetes(k8s)+DevOps企业级架构师实战培训

上一篇:同化云迁移策略的五个关键因素

下一篇:变压器厂家简介 Acme框架真香!用过一次后 伦敦博士撰文大赞DeepMind深化学习框架

Powered by 电竞菠菜分析 @2013-2021 RSS地图 HTML地图