日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從一個(gè)優(yōu)質(zhì)開源項(xiàng)目來(lái)看前端架構(gòu)

何為系統(tǒng)架構(gòu)師?

  • 系統(tǒng)架構(gòu)師是一個(gè)最終確認(rèn)和評(píng)估系統(tǒng)需求,給出開發(fā)規(guī)范,搭建系統(tǒng)實(shí)現(xiàn)的核心構(gòu)架,并澄清技術(shù)細(xì)節(jié)、掃清主要難點(diǎn)的技術(shù)人員。主要著眼于系統(tǒng)的“技術(shù)實(shí)現(xiàn)”。因此他/她應(yīng)該是特定的開發(fā)平臺(tái)、語(yǔ)言、工具的大師,對(duì)常見應(yīng)用場(chǎng)景能給出最恰當(dāng)?shù)慕鉀Q方案,同時(shí)要對(duì)所屬的開發(fā)團(tuán)隊(duì)有足夠的了解,能夠評(píng)估自己的團(tuán)隊(duì)實(shí)現(xiàn)特定的功能需求需要的代價(jià)。系統(tǒng)架構(gòu)師負(fù)責(zé)設(shè)計(jì)系統(tǒng)整體架構(gòu),從需求到設(shè)計(jì)的每個(gè)細(xì)節(jié)都要考慮到,把握整個(gè)項(xiàng)目,使設(shè)計(jì)的項(xiàng)目盡量效率高,開發(fā)容易,維護(hù)方便,升級(jí)簡(jiǎn)單等

    在和平等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站制作、網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需求定制制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站制作,營(yíng)銷型網(wǎng)站建設(shè),成都外貿(mào)網(wǎng)站建設(shè),和平網(wǎng)站建設(shè)費(fèi)用合理。

這是百度百科的答案

大多數(shù)人的問(wèn)題

如何成為一名前端架構(gòu)師?

  • 其實(shí),前端架構(gòu)師不應(yīng)該是一個(gè)頭銜,而應(yīng)該是一個(gè)過(guò)程。我記得掘金上有人寫過(guò)一篇文章:  《我在一個(gè)小公司,我把我們公司前端給架構(gòu)了》 , (我當(dāng)時(shí)還看成  《我把我們公司架構(gòu)師給上了》 )
  • 我面試過(guò)很多人,從小公司出來(lái)(我也是從一個(gè)很小很小的公司出來(lái),現(xiàn)在也沒(méi)在什么  BATJ ),最大的問(wèn)題在于,覺得自己不是  leader ,就沒(méi)有想過(guò)如何去提升、優(yōu)化項(xiàng)目,而是去研究一些花里胡哨的東西,卻沒(méi)有真正使用在項(xiàng)目中。(自然很少會(huì)有深度)
  • 在一個(gè)兩至三人的前端團(tuán)隊(duì)小公司,你去不斷優(yōu)化、提升項(xiàng)目體驗(yàn),更新迭代替換技術(shù)棧,那么你就是  前端架構(gòu)師

正式開始

我們從一個(gè)比較不錯(cuò)的項(xiàng)目入手,談?wù)勔粋€(gè)前端架構(gòu)師要做什么

  • SpaceX-API
  • SpaceX-API 是什么?
  • SpaceX-API 是一個(gè)用于火箭、核心艙、太空艙、發(fā)射臺(tái)和發(fā)射數(shù)據(jù)的開源 REST API(并且是使用Node.js編寫,我們用這個(gè)項(xiàng)目借鑒無(wú)可厚非)

 為了閱讀的舒適度,我把下面的正文盡量口語(yǔ)化一點(diǎn)

先把代碼搞下來(lái)

 
 
 
 
  1. git clone https://github.com/r-spacex/SpaceX-API.git 
  • 一個(gè)優(yōu)秀的開源項(xiàng)目搞下來(lái)以后,怎么分析它?大部分時(shí)候,你應(yīng)該先看它的目錄結(jié)構(gòu)以及依賴的第三方庫(kù)(  package.json 文件)

找到 package.json 文件的幾個(gè)關(guān)鍵點(diǎn):

  • main 字段(項(xiàng)目入口)
  • scripts 字段(執(zhí)行命令腳本)
  • dependencies和devDependencies字段(項(xiàng)目的依賴,區(qū)分線上依賴和開發(fā)依賴,我本人是非常看中這個(gè)點(diǎn),SpaceX-API也符合我的觀念,嚴(yán)格的區(qū)分依賴按照)
 
 
 
 
  1. "main": "server.js", 
  2.    "scripts": { 
  3.     "test": "npm run lint && npm run check-dependencies && jest --silent --verbose", 
  4.     "start": "node server.js", 
  5.     "worker": "node jobs/worker.js", 
  6.     "lint": "eslint .", 
  7.     "check-dependencies": "npx depcheck --ignores=\"pino-pretty\"" 
  8.   }, 
  • 通過(guò)上面可以看到,項(xiàng)目入口為  server.js
  • 項(xiàng)目啟動(dòng)命令為  npm run start
  • 幾個(gè)主要的依賴:

 
 
 
 
  1. "koa": "^2.13.0", 
  2.     "koa-bodyparser": "^4.3.0", 
  3.     "koa-conditional-get": "^3.0.0", 
  4.     "koa-etag": "^4.0.0", 
  5.     "koa-helmet": "^6.0.0", 
  6.     "koa-pino-logger": "^3.0.0", 
  7.     "koa-router": "^10.0.0", 
  8.     "koa2-cors": "^2.0.6", 
  9.     "lodash": "^4.17.20", 
  10.     "moment-range": "^4.0.2", 
  11.     "moment-timezone": "^0.5.32", 
  12.     "mongoose": "^5.11.8", 
  13.     "mongoose-id": "^0.1.3", 
  14.     "mongoose-paginate-v2": "^1.3.12", 
  15.     "eslint": "^7.16.0", 
  16.     "eslint-config-airbnb-base": "^14.2.1", 
  17.     "eslint-plugin-import": "^2.22.1", 
  18.     "eslint-plugin-jest": "^24.1.3", 
  19.     "eslint-plugin-mongodb": "^1.0.0", 
  20.     "eslint-plugin-no-secrets": "^0.6.8", 
  21.     "eslint-plugin-security": "^1.4.0", 
  22.     "jest": "^26.6.3", 
  23.     "pino-pretty": "^4.3.0" 

  • 都是一些通用主流庫(kù): 主要是koa框架,以及一些koa的一些中間件,monggose(連接使用mongoDB),eslint(代碼質(zhì)量檢查)

這里強(qiáng)調(diào)一點(diǎn),如果你的代碼需要兩人及以上維護(hù),我就強(qiáng)烈建議你不要使用任何黑魔法,以及不使用非主流的庫(kù),除非你編寫核心底層邏輯時(shí)候非用不可(這個(gè)時(shí)候應(yīng)該只有你維護(hù))

項(xiàng)目目錄 

  • 這是一套標(biāo)準(zhǔn)的  REST API, 嚴(yán)格分層
  • 幾個(gè)重點(diǎn)目錄 :

    • server.js 項(xiàng)目入口

    • app.js 入口文件

    • services 文件夾 => 項(xiàng)目提供服務(wù)層

    • scripts 文件夾 => 項(xiàng)目腳本

    • middleware 文件夾 => 中間件

    • docs 文件夾 =>文檔存放

    • tests 文件夾 => 單元測(cè)試代碼存放

    • .dockerignore docker的忽略文件

    • Dockerfile 執(zhí)行docker build命令讀取配置的文件

    • .eslintrc eslint配置文件

    • jobs 文件夾 => 我想應(yīng)該是對(duì)應(yīng)檢查他們api服務(wù)的代碼,里面都是準(zhǔn)備的一些參數(shù)然后直接調(diào)服務(wù)

逐個(gè)分析

從項(xiàng)目依賴安裝說(shuō)起

  • 安裝環(huán)境嚴(yán)格區(qū)分開發(fā)依賴和線上依賴,讓閱讀代碼者一目了然哪些依賴是線上需要的

 
 
 
 
  1. "dependencies": { 
  2.     "blake3": "^2.1.4", 
  3.     "cheerio": "^1.0.0-rc.3", 
  4.     "cron": "^1.8.2", 
  5.     "fuzzball": "^1.3.0", 
  6.     "got": "^11.8.1", 
  7.     "ioredis": "^4.19.4", 
  8.     "koa": "^2.13.0", 
  9.     "koa-bodyparser": "^4.3.0", 
  10.     "koa-conditional-get": "^3.0.0", 
  11.     "koa-etag": "^4.0.0", 
  12.     "koa-helmet": "^6.0.0", 
  13.     "koa-pino-logger": "^3.0.0", 
  14.     "koa-router": "^10.0.0", 
  15.     "koa2-cors": "^2.0.6", 
  16.     "lodash": "^4.17.20", 
  17.     "moment-range": "^4.0.2", 
  18.     "moment-timezone": "^0.5.32", 
  19.     "mongoose": "^5.11.8", 
  20.     "mongoose-id": "^0.1.3", 
  21.     "mongoose-paginate-v2": "^1.3.12", 
  22.     "pino": "^6.8.0", 
  23.     "tle.js": "^4.2.8", 
  24.     "tough-cookie": "^4.0.0" 
  25.   }, 
  26.   "devDependencies": { 
  27.     "eslint": "^7.16.0", 
  28.     "eslint-config-airbnb-base": "^14.2.1", 
  29.     "eslint-plugin-import": "^2.22.1", 
  30.     "eslint-plugin-jest": "^24.1.3", 
  31.     "eslint-plugin-mongodb": "^1.0.0", 
  32.     "eslint-plugin-no-secrets": "^0.6.8", 
  33.     "eslint-plugin-security": "^1.4.0", 
  34.     "jest": "^26.6.3", 
  35.     "pino-pretty": "^4.3.0" 
  36.   }, 

項(xiàng)目目錄劃分

  • 目錄劃分,嚴(yán)格分層

  • 通用,清晰簡(jiǎn)介明了,讓人一看就懂

正式開始看代碼

  • 入口文件,  server.js 開始
  •   
      
      
      
    1. const http = require('http'); 
    2. const mongoose = require('mongoose'); 
    3. const { logger } = require('./middleware/logger'); 
    4. const app = require('./app'); 
    5.  
    6. const PORT = process.env.PORT || 6673; 
    7. const SERVER = http.createServer(app.callback()); 
    8.  
    9. // Gracefully close Mongo connection 
    10. const gracefulShutdown = () => { 
    11.   mongoose.connection.close(false, () => { 
    12.     logger.info('Mongo closed'); 
    13.     SERVER.close(() => { 
    14.       logger.info('Shutting down...'); 
    15.       process.exit(); 
    16.     }); 
    17.   }); 
    18. }; 
    19.  
    20. // Server start 
    21. SERVER.listen(PORT, '0.0.0.0', () => { 
    22.   logger.info(`Running on port: ${PORT}`); 
    23.  
    24.   // Handle kill commands 
    25.   process.on('SIGTERM', gracefulShutdown); 
    26.  
    27.   // Prevent dirty exit on code-fault crashes: 
    28.   process.on('uncaughtException', gracefulShutdown); 
    29.  
    30.   // Prevent promise rejection exits 
    31.   process.on('unhandledRejection', gracefulShutdown); 
    32. }); 
  • 幾個(gè)優(yōu)秀的地方

    • 每個(gè)回調(diào)函數(shù)都會(huì)有聲明功能注釋

    • 像  SERVER.listen 的host參數(shù)也會(huì)傳入,這里是為了避免產(chǎn)生不必要的麻煩。至于這個(gè)麻煩,我這就不解釋了(一定要有能看到的默認(rèn)值,而不是去靠猜)
    • 對(duì)于監(jiān)聽端口啟動(dòng)服務(wù)以后一些異常統(tǒng)一捕獲,并且統(tǒng)一日志記錄,  process 進(jìn)程退出,防止出現(xiàn)僵死線程、端口占用等(因?yàn)閚ode部署時(shí)候可能會(huì)用pm2等方式,在 Worker 線程中,process.exit()將停止當(dāng)前線程而不是當(dāng)前進(jìn)程)

app.js入口文件

  • 這里是由  koa 提供基礎(chǔ)服務(wù)
  • monggose 負(fù)責(zé)連接  mongoDB 數(shù)據(jù)庫(kù)
  • 若干中間件負(fù)責(zé)跨域、日志、錯(cuò)誤、數(shù)據(jù)處理等

  •   
      
      
      
    1. const conditional = require('koa-conditional-get'); 
    2. const etag = require('koa-etag'); 
    3. const cors = require('koa2-cors'); 
    4. const helmet = require('koa-helmet'); 
    5. const Koa = require('koa'); 
    6. const bodyParser = require('koa-bodyparser'); 
    7. const mongoose = require('mongoose'); 
    8. const { requestLogger, logger } = require('./middleware/logger'); 
    9. const { responseTime, errors } = require('./middleware'); 
    10. const { v4 } = require('./services'); 
    11.  
    12. const app = new Koa(); 
    13.  
    14. mongoose.connect(process.env.SPACEX_MONGO, { 
    15.   useFindAndModify: false, 
    16.   useNewUrlParser: true, 
    17.   useUnifiedTopology: true, 
    18.   useCreateIndex: true, 
    19. }); 
    20.  
    21. const db = mongoose.connection; 
    22.  
    23. db.on('error', (err) => { 
    24.   logger.error(err); 
    25. }); 
    26. db.once('connected', () => { 
    27.   logger.info('Mongo connected'); 
    28.   app.emit('ready'); 
    29. }); 
    30. db.on('reconnected', () => { 
    31.   logger.info('Mongo re-connected'); 
    32. }); 
    33. db.on('disconnected', () => { 
    34.   logger.info('Mongo disconnected'); 
    35. }); 
    36.  
    37. // disable console.errors for pino 
    38. app.silent = true; 
    39.  
    40. // Error handler 
    41. app.use(errors); 
    42.  
    43. app.use(conditional()); 
    44.  
    45. app.use(etag()); 
    46.  
    47. app.use(bodyParser()); 
    48.  
    49. // HTTP header security 
    50. app.use(helmet()); 
    51.  
    52. // Enable CORS for all routes 
    53. app.use(cors({ 
    54.   origin: '*', 
    55.   allowMethods: ['GET', 'POST', 'PATCH', 'DELETE'], 
    56.   allowHeaders: ['Content-Type', 'Accept'], 
    57.   exposeHeaders: ['spacex-api-cache', 'spacex-api-response-time'], 
    58. })); 
    59.  
    60. // Set header with API response time 
    61. app.use(responseTime); 
    62.  
    63. // Request logging 
    64. app.use(requestLogger); 
    65.  
    66. // V4 routes 
    67. app.use(v4.routes()); 
    68.  
    69. module.exports = app; 
  • 邏輯清晰,自上而下,首先連接db數(shù)據(jù)庫(kù),掛載各種事件后,經(jīng)由koa各種中間件,而后真正使用koa路由提供api服務(wù)(代碼編寫順序,即代碼運(yùn)行后的業(yè)務(wù)邏輯,我們寫前端的react等的時(shí)候,也提倡由生命周期運(yùn)行順序去編寫組件代碼,而不是先編寫unmount生命周期,再編寫mount),例如應(yīng)該這樣:
 
 
 
 
  1. //組件掛載 
  2. componentDidmount(){ 
  3.  
  4. //組件需要更新時(shí) 
  5. shouldComponentUpdate(){ 
  6.  
  7. //組件將要卸載 
  8. componentWillUnmount(){ 
  9.  
  10. ... 
  11. render(){} 

router的代碼,簡(jiǎn)介明了

 
 
 
 
  1. const Router = require('koa-router'); 
  2. const admin = require('./admin/routes'); 
  3. const capsules = require('./capsules/routes'); 
  4. const cores = require('./cores/routes'); 
  5. const crew = require('./crew/routes'); 
  6. const dragons = require('./dragons/routes'); 
  7. const landpads = require('./landpads/routes'); 
  8. const launches = require('./launches/routes'); 
  9. const launchpads = require('./launchpads/routes'); 
  10. const payloads = require('./payloads/routes'); 
  11. const rockets = require('./rockets/routes'); 
  12. const ships = require('./ships/routes'); 
  13. const users = require('./users/routes'); 
  14. const company = require('./company/routes'); 
  15. const roadster = require('./roadster/routes'); 
  16. const starlink = require('./starlink/routes'); 
  17. const history = require('./history/routes'); 
  18. const fairings = require('./fairings/routes'); 
  19.  
  20. const v4 = new Router({ 
  21.   prefix: '/v4', 
  22. }); 
  23.  
  24. v4.use(admin.routes()); 
  25. v4.use(capsules.routes()); 
  26. v4.use(cores.routes()); 
  27. v4.use(crew.routes()); 
  28. v4.use(dragons.routes()); 
  29. v4.use(landpads.routes()); 
  30. v4.use(launches.routes()); 
  31. v4.use(launchpads.routes()); 
  32. v4.use(payloads.routes()); 
  33. v4.use(rockets.routes()); 
  34. v4.use(ships.routes()); 
  35. v4.use(users.routes()); 
  36. v4.use(company.routes()); 
  37. v4.use(roadster.routes()); 
  38. v4.use(starlink.routes()); 
  39. v4.use(history.routes()); 
  40. v4.use(fairings.routes()); 
  41.  
  42. module.exports = v4; 

模塊眾多,找?guī)讉€(gè)代表性的模塊

  • admin 模塊
 
 
 
 
  1. const Router = require('koa-router'); 
  2. const { auth, authz, cache } = require('../../../middleware'); 
  3.  
  4. const router = new Router({ 
  5.   prefix: '/admin', 
  6. }); 
  7.  
  8. // Clear redis cache 
  9. router.delete('/cache', auth, authz('cache:clear'), async (ctx) => { 
  10.   try { 
  11.     await cache.redis.flushall(); 
  12.     ctx.status = 200; 
  13.   } catch (error) { 
  14.     ctx.throw(400, error.message); 
  15.   } 
  16. }); 
  17.  
  18. // Healthcheck 
  19. router.get('/health', async (ctx) => { 
  20.   ctx.status = 200; 
  21. }); 
  22.  
  23. module.exports = router; 
  • 分析代碼

  •  這是一套標(biāo)準(zhǔn)的restful API ,提供的/admin/cache接口,請(qǐng)求方式為delete,請(qǐng)求這個(gè)接口,首先要經(jīng)過(guò)auth和authz兩個(gè)中間件處理

這里補(bǔ)充一個(gè)小細(xì)節(jié)

  • 一個(gè)用戶訪問(wèn)一套系統(tǒng),有兩種狀態(tài),未登陸和已登陸,如果你未登陸去執(zhí)行一些操作,后端應(yīng)該返回  401 。但是登錄后,你只能做你權(quán)限內(nèi)的事情,例如你只是一個(gè)打工人,你說(shuō)你要關(guān)閉這個(gè)公司,那么對(duì)不起,你的狀態(tài)碼此時(shí)應(yīng)該是  403

回到admin

  • 此刻的你,想要清空這個(gè)緩存,調(diào)用/admin/cache接口,那么首先要經(jīng)過(guò)  auth 中間件判斷你是否有登錄
 
 
 
 
  1. /** 
  2.  * Authentication middleware 
  3.  */ 
  4. module.exports = async (ctx, next) => { 
  5.   const key = ctx.request.headers['spacex-key']; 
  6.   if (key) { 
  7.     const user = await db.collection('users').findOne({ key }); 
  8.     if (user?.key === key) { 
  9.       ctx.state.roles = user.roles; 
  10.       await next(); 
  11.       return; 
  12.     } 
  13.   } 
  14.   ctx.status = 401; 
  15.   ctx.body = 'https://youtu.be/RfiQYRn7fBg'; 
  16. }; 
  • 如果沒(méi)有登錄過(guò),那么意味著你沒(méi)有權(quán)限,此時(shí)為401狀態(tài)碼,你應(yīng)該去登錄.如果登錄過(guò),那么應(yīng)該前往下一個(gè)中間件  authz 。 (所以redux的中間件源碼是多么重要。它可以說(shuō)貫穿了我們整個(gè)前端生涯,我以前些過(guò)它的分析,有興趣的可以翻一翻公眾號(hào))
  •   
      
      
      
    1. /** 
    2.  * Authorization middleware 
    3.  * 
    4.  * @param   {String}   role   Role for protected route 
    5.  * @returns {void} 
    6.  */ 
    7. module.exports = (role) => async (ctx, next) => { 
    8.   const { roles } = ctx.state; 
    9.   const allowed = roles.includes(role); 
    10.   if (allowed) { 
    11.     await next(); 
    12.     return; 
    13.   } 
    14.   ctx.status = 403; 
    15. }; 
  •  在authz這里會(huì)根據(jù)你傳入的操作類型(這里是'cache:clear'),看你的對(duì)應(yīng)所有權(quán)限r(nóng)oles里面是否包含傳入的操作類型role 。如果沒(méi)有,就返回403,如果有,就繼續(xù)下一個(gè)中間件 - 即真正的/admin/cache接口
 
 
 
 
  1. // Clear redis cache 
  2. router.delete('/cache', auth, authz('cache:clear'), async (ctx) => { 
  3.   try { 
  4.     await cache.redis.flushall(); 
  5.     ctx.status = 200; 
  6.   } catch (error) { 
  7.     ctx.throw(400, error.message); 
  8.   } 
  9. }); 
  • 此時(shí)此刻,使用try catch包裹邏輯代碼,當(dāng)redis清除所有緩存成功即會(huì)返回狀態(tài)碼400,如果報(bào)錯(cuò),就會(huì)拋出錯(cuò)誤碼和原因。接由洋蔥圈外層的  error 中間件處理
 
 
 
 
  1. /** 
  2.  * Error handler middleware 
  3.  * 
  4.  * @param   {Object}    ctx       Koa context 
  5.  * @param   {function}  next      Koa next function 
  6.  * @returns {void} 
  7.  */ 
  8. module.exports = async (ctx, next) => { 
  9.   try { 
  10.     await next(); 
  11.   } catch (err) { 
  12.     if (err?.kind === 'ObjectId') { 
  13.       err.status = 404; 
  14.     } else { 
  15.       ctx.status = err.status || 500; 
  16.       ctx.body = err.message; 
  17.     } 
  18.   } 
  19. }; 
  • 這樣只要任意的  server 層內(nèi)部出現(xiàn)異常,只要拋出,就會(huì)被  error 中間件處理,直接返回狀態(tài)碼和錯(cuò)誤信息. 如果沒(méi)有傳入狀態(tài)碼,那么默認(rèn)是500(所以我之前說(shuō)過(guò),代碼要穩(wěn)定,一定要有顯示的指定默認(rèn)值,要關(guān)注代碼異常的邏輯,例如前端setLoading,請(qǐng)求失敗也要取消loading,不然用戶就沒(méi)法重試了,有可能這一瞬間只是用戶網(wǎng)絡(luò)出錯(cuò)呢)

補(bǔ)一張koa洋蔥圈的圖

再接下來(lái)看其他的services

  • 現(xiàn)在,都非常輕松就能理解了

 
 
 
 
  1. // Get one history event 
  2. router.get('/:id', cache(300), async (ctx) => { 
  3.   const result = await History.findById(ctx.params.id); 
  4.   if (!result) { 
  5.     ctx.throw(404); 
  6.   } 
  7.   ctx.status = 200; 
  8.   ctx.body = result; 
  9. }); 
  10.  
  11. // Query history events 
  12. router.post('/query', cache(300), async (ctx) => { 
  13.   const { query = {}, options = {} } = ctx.request.body; 
  14.   try { 
  15.     const result = await History.paginate(query, options); 
  16.     ctx.status = 200; 
  17.     ctx.body = result; 
  18.   } catch (error) { 
  19.     ctx.throw(400, error.message); 
  20.   } 
  21. }); 


通過(guò)這個(gè)項(xiàng)目,我們能學(xué)到什么

  • 一個(gè)能上天的項(xiàng)目,必然是非常穩(wěn)定、高可用的,我們首先要學(xué)習(xí)它的優(yōu)秀點(diǎn):用最簡(jiǎn)單的技術(shù)加上最簡(jiǎn)單的實(shí)現(xiàn)方式,讓人一眼就能看懂它的代碼和分層

  • 再者:簡(jiǎn)潔的注釋是必要的

  • 從業(yè)務(wù)角度去抽象公共層,例如鑒權(quán)、錯(cuò)誤處理、日志等為公共模塊(中間件,前端可能是一個(gè)工具函數(shù)或組件)

  • 多考慮錯(cuò)誤異常的處理,前端也是如此,js大多錯(cuò)誤發(fā)生來(lái)源于a.b.c這種代碼(如果a.b為undefined那么就會(huì)報(bào)錯(cuò)了)
  • 顯示的指定默認(rèn)值,不讓代碼閱讀者去猜測(cè)

  • 目錄分區(qū)必定要簡(jiǎn)潔明了,分層清晰,易于維護(hù)和拓展

成為一個(gè)優(yōu)秀前端架構(gòu)師的幾個(gè)技能點(diǎn)

  • 原生JavaScript、CSS、HTML基礎(chǔ)扎實(shí)(系統(tǒng)學(xué)習(xí)過(guò))

  • 原生Node.js基礎(chǔ)扎實(shí)(系統(tǒng)學(xué)習(xí)過(guò)),Node.js不僅提供服務(wù),更多的是用于制作工具,以及現(xiàn)在serverless場(chǎng)景也會(huì)用到,還有SSR

  • 熟悉框架和類庫(kù)原理,能手寫簡(jiǎn)易的常用類庫(kù),例如promise redux 等

  • 數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)扎實(shí),了解常用、常見算法

  • linux基礎(chǔ)扎實(shí)(做工具,搭環(huán)境,編寫構(gòu)建腳本等有會(huì)用到)

  • 熟悉TCP和http等通信協(xié)議

  • 熟悉操作系統(tǒng)linux Mac windows iOS 安卓等(在跨平臺(tái)產(chǎn)品時(shí)候會(huì)遇到)

  • 會(huì)使用docker(部署相關(guān))

  • 會(huì)一些c++最佳(在addon場(chǎng)景等,再者Node.js和JavaScript本質(zhì)上是基于  C++ )
  • 懂基本數(shù)據(jù)庫(kù)、redis、nginxs操作,像跨平臺(tái)產(chǎn)品,基本前端都會(huì)有個(gè)sqlite之類的,像如果是node自身提供服務(wù),數(shù)據(jù)庫(kù)和redis一般少不了

  • 再者是要多閱讀優(yōu)秀的開源項(xiàng)目源碼,不用太多,但是一定要精

文章題目:從一個(gè)優(yōu)質(zhì)開源項(xiàng)目來(lái)看前端架構(gòu)
文章源于:http://www.dlmjj.cn/article/cdgdjdc.html