轉帖|行業資訊|編輯:龔雪|2017-03-01 11:34:33.000|閱讀 190 次
概述:在這篇中,筆者會列出 2017 年成為更好 Node 開發者的技巧的大綱。這些技巧一部分是在具體實踐中總結得出的,一部分借鑒了 Node 和 npm 優秀模塊開發者的經驗。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
注意: 這篇文章之前的標題是 “來自平臺大神的最佳實踐分享”。文章內容是經過實際的測試和試驗寫出,但并非 2017 年最新技巧。 雖然,Node 大神分享的最佳經典實踐在 2017 年,2018 年甚至 2019 年都會受用,但一些尖端功能,像 async/await, promises 并沒有涵蓋在內。因為這些新特性不在 Node 核心代碼中,也不如 npm 和 Express 流行。文章第二部分,我將介紹此文章的性質。
我開始作為全職Node開發是在2012年,當我加入了Storify公司。 從那時起,我從沒有回頭或者覺得掛念Python,Ruby,Java和PHP——這些貫穿我之前十年web開發工作的語言。
Storify對我來說是一份有趣的工作,因為不像大多數公司, Storify所有的項目運行(也許今后依舊)都是使用Javascript。你看,大多數公司,尤其是大公司如貝寶(PayPal)、沃爾瑪(Walmart)、或第一資本(Capital One),只是使用Node作為他們堆棧的某部分。通常他們使用它作為API途徑或一個業務流程層。這也是不錯的,但是對于一個軟件工程師來說,沒有什么比完全沉浸在一個Node環境中更棒的了。
我這篇博客中,我會列出 2017 年成為更好 Node 開發者的技巧的大綱。這些技巧一部分是我在具體實踐中總結得出的,一部分借鑒了 Node 和 npm 優秀模塊開發者的經驗。主要內容如下:
下面,讓我們對每項內容都進行一下了解吧~
避免復雜性
npm 的作者 Isaac Z. Schlueter 寫了一些模板,我們可以看下。例如, 用 在模塊中強制實施 JavaScript 嚴格模式,只需要三行代碼:
var module = require('module') module.wrapper[0] += '"use strict";' Object.freeze(module.wrap)
那么,為什么要避免復雜性呢? 美國海軍傳說中,有一句很著名的話:化繁為簡,返璞歸真(或理解為“編碼的方式簡單點,傻蛋!”)事實證明,人類大腦一次只能記住 5 項至 7項的內容,這就是此處要求簡單的原因。
縮小代碼模塊,有利于你和開發者更好地理解代碼,你也能更好地進行測試。參考以下示例:
app.use(function(req, res, next) { if (req.session.admin === true) return next() else return next(new Error('Not authorized')) }, function(req, res, next) { req.db = db next() })
或如下代碼:
const auth = require('./middleware/auth.js') const db = require('./middleware/db.js')(db) app.use(auth, db)
我相信大多數的讀者都更喜歡第二個示例,尤其是在名稱可以自解釋時。當然,在你寫代碼時,你能理解它的運行方式。或許,你還會為能將如此多的方法用在一行代碼中而沾沾自喜。但是,代碼不會說話啊。如果你把代碼寫的復雜而嚴謹,當你時隔六個月再來看,或者某天你睡迷糊了或喝醉了來看,理解起它們來會非常困難,更不要說根本不了解其算法和復雜性的同事了。保持簡單,這一準則在使用 Node 異步方式的時候特別受用。
有一種 ,不過它只影響了依賴公共注冊表的項目,并在 11 分鐘之后重新發布。最小化所帶來的益處遠大于其缺點。而且,npm 已經,任何重要的項目都應該使用緩存或私有注冊中心(作為臨時解決方案)。
使用異步代碼
同步代碼確實在 Node 中有一個(低的)位置。 它主要用于編寫 CLI 命令或與 Web 應用程序無關的其他腳本。Node 開發者主要構建 Web 應用程序,因此他們使用異步代碼,以避免阻塞線程。
例如,這可能是可行的,如果我們只是建立一個數據庫腳本,而不是一個系統來處理并行/并發任務:
let data = fs.readFileSync('./acconts.json') db.collection('accounts').insert(data, (results))=>{ fs.writeFileSync('./accountIDs.json', results, ()=>) })
但當建立一個Web應用程序時,這樣寫會更好:
app.use('/seed/:name', (req, res) => { let data = fs.readFile(`./$.json`, ()=>{ db.collection(req.params.name).insert(data, (results))=>{ fs.writeFile(`./$IDs.json`, results, ()=) }) }) })
區別就在于你是寫并發系統(長期運行)還是非并發系統(短期運行)。根據實踐經驗,我們通常在 Node 中使用異步代碼。
避免阻塞請求
Node 有個簡單的模板加載系統,它使用的是 CommonJS 模板規范。它內置的 require 函數是將單獨存放的模板包含進來的簡易方式。不像 AMD/requirejs,Node/CommonJS 的模板加載方式是同步的。require 的工作原理:導入在模板或文件中導出的內容。
const react = require('react')
大多數開發者都不知道 require 有緩存。因此,只要解析的域名沒有變化(在 nmp 模板中是沒有的), 模塊中的代碼會只執行一次并將結果保存在一個變量中(同一進程內)。這是一個很不錯的優化。然而,即使在緩存的情況下,你也最好把 require 語句放在前面。 看看下面的代碼,在真正進入路由的時候才加載 axios 模塊。/connect 路由出乎預料的慢,因為它在導入模塊的時候才開始請求文件:
app.post('/connect', (req, res) => { const axios = require('axios') axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) })
更好更高效的方式是服務器啟動后就加載模塊,而不是在路由中:
const axios = require('axios') const express = require('express') app = express() app.post('/connect', (req, res) => { axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) })
了解 require 可被緩存
我在上面提到過 require 可緩存,但有趣的是我們可以在 module.exports 外部進行編碼,比如:
console.log('I will not be cached and only run once, the first time') module.exports = () => { console.log('I will be cached and will run every time this module is invoked') }
知道有些代碼只運行一次,你可以將這一特點作為優勢。
時刻檢查錯誤
Node 不是 Java,在 Java 中,你可以拋出錯誤,因為大多數時候,當你發現錯誤時,你會中止應用程序的運行。并且,在 Java 中,你可以通過單獨的 try...catch 處理多個錯誤。
但 Node 不是這樣。因為 Node 使用的是事件循環和異步執行,在錯誤發生時,任何錯誤都與錯誤處理程序的上下文分離(比如 try...catch)。下述代碼在 Node 中無效:
try { request.get('/accounts', (error, response)=>{ data = JSON.parse(response) }) } catch(error) { // Will NOT be called console.error(error) }
但 try...catch 也可在 Node 同步代碼中使用。因此,這是重構前面代碼段的更好的方式:
request.get('/accounts', (error, response)=>{ try { data = JSON.parse(response) } catch(error) { // Will be called console.error(error) } })
如果我們不能將 request 調用放在 try...catch 塊中,我們就不能處理來自 request 的錯誤。Node 開發者采用提供包含 error 參數的回調來解決這個問題。這樣你需要在每個回調中手工處理錯誤。你需要檢查 error(確保它不是 null),然后將相應的錯誤消息顯示給用戶或者客戶端,并記錄下來。也可以通過調用棧中的 callback 往回傳(如果你有回調,而且調用棧上還有另一個函數)。
request.get('/accounts', (error, response)=>{ if (error) return console.error(error) try { data = JSON.parse(response) } catch(error) { console.error(error) } })
你還可以使用 庫。 你可以使用以下代碼來避免在無數回調中出現手動檢查的誤差。 (Hello, ).
var ok = require('okay') request.get('/accounts', ok(console.error, (response)=>{ try { data = JSON.parse(response) } catch(error) { console.error(error) } }))
返回回調或使用 if … else
Node 是并發的。因此它有個特點就是,如果不加以注意,就會出現 bug。安全起見,我們使用 return 語句終止執行:
let error = true if (error) return callback(error) console.log('I will never run - good.')
避免由于錯誤的控制流導致的一些無意的并發(和失敗操作)。
let error = true if (error) callback(error) console.log('I will run. Not good!')
確保返回一個回調,以防止繼續執行。
監聽錯誤事件
幾乎所有的 Node 類/對象都擴展了事件發射器(觀察者模式)并發出錯誤事件。 在錯位被破壞之前,這給開發人員提供了捕獲錯誤并處理的機會。
養成使用 .on() 為錯誤創建事件偵聽器的好習慣
var req = http.request(options, (res) => { if (('' + res.statusCode).match(/^2\d\d$/)) { // Success, process response } else if (('' + res.statusCode).match(/^5\d\d$/)) // Server error, not the same as req error. Req was ok. } }) req.on('error', (error) => { // Can't even make a request: general error, e.g. ECONNRESET, ECONNREFUSED, HPE_INVALID_VERSION console.log(error) })
了解 npm
很多 Node 開發者和前端開發者都知道—— save(npm install 參數)可以安裝一個模板,但要在 package.json 記錄模板的版本。當然,還有 save-dev, 用于在 devDependencies 添加記錄 (記錄生產中不需要的模板)。但你知道用 -S 和 -D 代替 --save 和 --save-dev 嗎?你不妨試試。
在安裝模塊的時候,去刪除 -S 和 -D 為你添加的那些 ^ 記號。它們非常危險,因為它們允許 npm install(或簡寫為 npm i)從 npm 庫中拉取最新的小版本(語義化的版本號中的第2個數)。比如從 v6.1.0 到 v6.2.0 就是一個小版本發布。
npm 團隊信任 ,但你不能。他們加上 ^ 符號是因為他們相信開源作者不會在小版本中引入破壞性的修改。然而明眼人都知道它是不可靠的。你應該鎖定版本號,最好使用 shrinkwrap:npm shrinkwrap 創建一個包含依賴的具體版本的新文件。
結語
這篇博客只是第一部分,其中已經涵蓋了很多內容,從回調函數和異步代碼的使用,到錯誤的檢查和依賴的鎖定。希望這篇文章能給你帶來新的啟示。(作者:Azat Mardan ;翻譯:可譯網)
更多行業資訊,更新鮮的技術動態,盡在。
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn