這篇文章主要講解了“Node.js有哪些特性”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Node.js有哪些特性”吧!
增城網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),增城網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為增城千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營銷網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的增城做網(wǎng)站的公司定做!
為何用Node
對于我來說,對于團(tuán)隊來說,適用Node的原因其實(shí)很簡單:開發(fā)起來快。熟悉JS的前端同學(xué)可以很快上手,節(jié)省成本。選一個http server庫起一個server,選擇合適的中間件,匹配好請求路由,看情況合理使用ORM庫鏈接數(shù)據(jù)庫、增刪改查即可。
Node的適用場景
Node.js 使用了一個事件驅(qū)動、非阻塞式 I/O 的模型,使其輕量又高效。這種模型使得Node.js 可以避免了由于需要等待輸入或者輸出(數(shù)據(jù)庫、文件系統(tǒng)、Web服務(wù)器...)響應(yīng)而造成的 CPU 時間損失。所以,Node.js適合運(yùn)用在高并發(fā)、I/O密集、少量業(yè)務(wù)邏輯的場景。
對應(yīng)到平時具體的業(yè)務(wù)上,如果是內(nèi)部的系統(tǒng),大部分僅僅就是需要對某個數(shù)據(jù)庫進(jìn)行增刪改查,那么Server端直接就是Node.js一把梭。
對于線上業(yè)務(wù),如果流量不大,并且業(yè)務(wù)邏輯簡單的情況下,Server端也可以完全使用Node.js。對于流量巨大,復(fù)雜度高的項(xiàng)目,一般用Node.js作為接入層,后臺同學(xué)負(fù)責(zé)實(shí)現(xiàn)服務(wù)。如下圖:
同樣是寫JS,Node.js開發(fā)和頁面開發(fā)有什么區(qū)別
在瀏覽器端開發(fā)頁面,是和用戶打交道、重交互,瀏覽器還提供了各種Web Api供我們使用。Node.js主要面向數(shù)據(jù),收到請求后,返回具體的數(shù)據(jù)。這是兩者在業(yè)務(wù)路徑上的區(qū)別。而真正的區(qū)別其實(shí)是在于業(yè)務(wù)模型上(業(yè)務(wù)模型,這是我自己瞎想的一個詞)。直接用圖表示吧。
開發(fā)頁面時,每一個用戶的瀏覽器上都有一份JS代碼。如果代碼在某種情況下崩了,只會對當(dāng)前用戶產(chǎn)生影響,并不會影響其他用戶,用戶刷新一下即可恢復(fù)。而在Node.js中,在不開啟多進(jìn)程的情況下,所有用戶的請求,都會走進(jìn)同一份JS代碼,并且只有一個線程在執(zhí)行這份JS代碼。如果某個用戶的請求,導(dǎo)致發(fā)生錯誤,Node.js進(jìn)程掛掉,server端直接就掛了。盡管可能有進(jìn)程守護(hù),掛掉的進(jìn)程會被重啟,但是在用戶請求量大的情況下,錯誤會被頻繁觸發(fā),可能就會出現(xiàn)server端不停掛掉,不停重啟的情況,對用戶體驗(yàn)造成影響。
以上,可能是Node.js開發(fā)和前端JS開發(fā)最大的區(qū)別。
Node.js開發(fā)時的注意事項(xiàng)
用戶在訪問Node.js服務(wù)時,如果某一個請求卡住了,服務(wù)遲遲不能返回結(jié)果,或者說邏輯出錯,導(dǎo)致服務(wù)掛掉,都會帶來大規(guī)模的體驗(yàn)問題。server端的目標(biāo),就是要 快速、可靠 地返回數(shù)據(jù)。
緩存
由于Node.js不擅長處理復(fù)雜邏輯(JavaScript本身執(zhí)行效率較低),如果要用Node.js做接入層,應(yīng)該避免復(fù)雜的邏輯。想要快速處理數(shù)據(jù)并返回,一個至關(guān)重要的點(diǎn):使用緩存。
例如,使用Node做React同構(gòu)直出,renderToString這個Api,可以說是比較重的邏輯了。如果頁面的復(fù)雜度高,每次請求都完整執(zhí)行renderToString,會長時間占用線程來執(zhí)行代碼,增加響應(yīng)時間,降低服務(wù)的吞吐量。這個時候,緩存就十分重要了。
實(shí)現(xiàn)緩存的主要方式:內(nèi)存緩存??梢允褂肕ap,WeakMap,WeakRef等實(shí)現(xiàn)。參考以下簡單的示例代碼:
const cache = new Map(); router.get('/getContent', async (req, res) => { const id = req.query.id; // 命中緩存 if(cache.get(id)) { return res.send(cache.get(id)); } // 請求數(shù)據(jù) const rsp = await rpc.get(id); // 經(jīng)過一頓復(fù)雜的操作,處理數(shù)據(jù) const content = process(rsp); // 設(shè)置緩存 cache.set(id, content); return res.send(content); });
使用緩存時,有一個很重要的問題是:內(nèi)存緩存如何更新。一種最簡單的方法,開一個定時器,定期刪除緩存,下一次請求到來時,重新設(shè)置緩存即可。在上述代碼中,增加如下代碼:
setTimeout(function() { cache.clear(); }, 1000 * 60); // 1分鐘刪除一次緩存
如果server端完全使用Node實(shí)現(xiàn),需要用Node端直接連接數(shù)據(jù)庫,在數(shù)據(jù)時效性要求不太高、且流量不太大的情況下,就可以使用上述類似的模型,如下圖。這樣可以降低數(shù)據(jù)庫的壓力且加快Node的響應(yīng)速度。
另外,還需要注意內(nèi)存緩存的大小。如果一直往緩存里寫入新數(shù)據(jù),那么內(nèi)存會越來越大,最終爆掉??梢钥紤]使用LRU(Least Recently Used)算法來做緩存。開辟一塊內(nèi)存專門作為緩存區(qū)域。當(dāng)緩存大小達(dá)到上限時,淘汰最久未使用的緩存。
內(nèi)存緩存會隨著進(jìn)程的重啟而全部失效。
當(dāng)后臺業(yè)務(wù)比較復(fù)雜,接入層流量,數(shù)據(jù)量較大時,可以使用如下的架構(gòu),使用獨(dú)立的內(nèi)存緩存服務(wù)。Node接入層直接從緩存服務(wù)取數(shù)據(jù),后臺服務(wù)直接更新緩存服務(wù)。
當(dāng)然,上圖中的架構(gòu)是最簡單的情形,現(xiàn)實(shí)中還需要考慮分布式緩存、緩存一致性的問題。這又是另外一個話題了。
錯誤處理
由于Node.js語言的特性,Node服務(wù)是比較容易出錯的。而一旦出錯,造成的影響就是服務(wù)不可用。因此,對于錯誤的處理十分的重要。
處理錯誤,最常用的就是try catch 了??墒?try catch無法捕獲異步錯誤。Node.js中,異步操作是十分常見的,異步操作主要是在回調(diào)函數(shù)中暴露錯誤??匆粋€例子:
const readFile = function(path) { return new Promise((resolve,reject) => { fs.readFile(path, (err, data) => { if(err) { throw err; // catch無法捕獲錯誤,這和Node的eventloop有關(guān)。 // reject(err); // catch可以捕獲 } resolve(data); }); }); } router.get('/xxx', async function(req, res) { try { const res = await readFile('xxx'); ... } catch (e){ // 捕獲錯誤處理 ... res.send(500); } });
上面的代碼中,readFile 中 throw 出來的錯誤,是無法被catch捕獲的。如果我們把 throw err 換成 Promise.reject(err),catch中是可以捕獲到錯誤的。
我們可以把異步操作都Promise化,然后統(tǒng)一使用 async 、try、catch 來處理錯誤。
但是,總會有地方會被遺漏。這個時候,可以使用process來捕獲全局錯誤,防止進(jìn)程直接退出,導(dǎo)致后面的請求掛掉。示例代碼:
process.on('uncaughtException', (err) => { console.error(`${err.message}\n${err.stack}`); }); process.on('unhandledRejection', (reason, p) => { console.error(`Unhandled Rejection at: Promise ${p} reason: `, reason); });
關(guān)于Node.js中錯誤的捕獲,還可以使用domain模塊?,F(xiàn)在這個模塊已經(jīng)不推薦使用了,我也沒有在項(xiàng)目中實(shí)踐過,這里就不展開了。Node.js 近幾年推出的 async_hooks 模塊,也還處于實(shí)驗(yàn)階段,不太建議線上環(huán)境直接使用。做好進(jìn)程守護(hù),開啟多進(jìn)程,錯誤告警及時修復(fù),養(yǎng)成良好的編碼規(guī)范,使用合適的框架,才能提高Node服務(wù)的效率及穩(wěn)定性。
感謝各位的閱讀,以上就是“Node.js有哪些特性”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Node.js有哪些特性這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!