摘要:不知不覺的已經(jīng)用有將近一年了,這里我有幾條出自實踐的建議送給剛剛?cè)腴T的的朋友。命名而不是匿名在中,我們可以創(chuàng)建匿名對象和匿名函數(shù)。一般來說,匿名函數(shù)可以讓代碼更加簡短精悍。然而,對這些對象或函數(shù)進行命名,則有利于調(diào)試和優(yōu)化。
不知不覺的已經(jīng)用Node.js有將近一年了,這里我有幾條出自實踐的node.js建議送給剛剛?cè)腴T的node.js的朋友。
命名而不是匿名在JavaScript中,我們可以創(chuàng)建匿名對象和匿名函數(shù)。一般來說,匿名函數(shù)可以讓代碼更加簡短精悍。
然而,對這些對象或函數(shù)進行命名,則有利于調(diào)試和優(yōu)化。以下是我從Chrome DevTool的文章中借用的圖片:
很明顯,命名的實體更利于調(diào)試和優(yōu)化。
盡早解引用JavaScript的GC以一種類似引用計數(shù)的算法工作,一個對象當(dāng)且僅當(dāng)所有指向它的引用全部釋放之后,它本身才會被釋放掉。
然而可能你有其他的閉包或者全局對象持有它的引用,從而阻止了垃圾回收。為避免這一現(xiàn)象,應(yīng)當(dāng)盡早地解除不必要的引用:
var some_var = new net.Server(); // other code... var i_want_it_temperoray = some_var; some_operation(i_want_it_temperoray); i_want_it_temperoray = null; // derefernce // other code...
如果閉包中尚有一個變量未能被釋放,那么整個閉包都有可能無法被回收,從而造成其它對象也無法釋放。
現(xiàn)在有很多工具可以輔助我們監(jiān)視內(nèi)存的變化情況,比如heapdump、webkit-devtools-agent等等。同時,這也更加說明了為什么要盡可能使用命名而不是匿名的對象。
別復(fù)制代碼我用Node.js開發(fā)的項目代碼變化非常快,重構(gòu)也很頻繁,常常會到處復(fù)制代碼。然而每當(dāng)我這樣做的時候,后來都會發(fā)現(xiàn)某些變量要么就是忘了改名,要么就是有些變量壓根就不存在了,導(dǎo)致代碼變得極為不穩(wěn)定。
JS是一門高度動態(tài)的語言,它不像C++這樣可以利用編譯器做靜態(tài)檢查,因此你幾乎沒有機會依靠工具檢查出這些問題。所以我的建議是,盡可能地自己再輸入一遍代碼,這樣IDE或者編輯器有機會利用代碼自動補全來為你檢查。如果你的IDE還沒這功能,那你真得考慮換掉它了。
慎重引入新模塊Node.js社區(qū)非常活躍,有成千上萬的現(xiàn)成模塊可以取用,然而其中有些其實已經(jīng)沒人管了。Node.js的API也常常發(fā)生變化,適配node v0.8.x的模塊,有可能不支持v0.10.x。
因此當(dāng)你考慮引入新的模塊的時候,務(wù)必先去它的pull request列表或者issue列表看看,確認一下這個模塊是不是已經(jīng)被拋棄,或者存在重大的隱患。
用async.js或者promiseNode.js基于回調(diào)。因為回調(diào)的本質(zhì),我們很容易寫出嵌套多層的回調(diào)函數(shù)。回調(diào)對于異步來說是好事,但對于代碼維護來說卻是壞事。
如果你發(fā)現(xiàn)代碼需要3層以上的回調(diào)函數(shù)嵌套,那你應(yīng)該考慮一下,要不要使用async.js或者基于promise概念的模塊。
以下是一個用async.js寫出來的一系列異步操作:
async.auto([ "init_logger": function(done){ set_handlers_to_logger(done); }, "load_config": ["init_logger", function(done){ load_my_config(done); }], "init_database": ["load_config", function(done){ connect_to_db_here(done); }], // 假定open_cache與數(shù)據(jù)庫無關(guān) "open_cache": ["load_config", function(done){ open_cache_here(done); }], // warm_up通常用于從數(shù)據(jù)庫預(yù)先抓取一些數(shù)據(jù) // 注意,warm_up只會在"init_database"以及"open_cache"結(jié)束后執(zhí)行 "warm_up": ["init_database", "open_cache", function(done){ fetch_some_data(done); }], "init_routers": ["load_config", function(done){ install_routers(done); }], "emit_out": ["warm_up", "init_routers", function(done){ notify_others(done); }] ], function(err) { if(err){ // 在這處理異常 } });
我對promise相關(guān)的模塊不是很熟,但使用Q,應(yīng)該可以寫出這樣的代碼,,同樣易于閱讀:
Q.nfcall(function init_logger(){ set_handlers_to_logger(); }) .then(function load_config(){ load_my_config(); }) .then(function init_database(){ connect_to_db_here(); }) .then(function open_cache(){ open_cache_here(); }) .then(function warm_up(){ fetch_some_data(); }) .then(function init_routers(){ install_routers(); }) .then(function emit_out(){ notify_others(); }) .catch(function (error) { // 在這處理異常 }) .done();
選取什么樣的庫來簡化邏輯一般都是隨便你。通常來說,async.js非常簡單,而Q則更加靈活強大。
比如說async.js中各個函數(shù)獨立而不嵌套,因此如果你想通過捕獲某個函數(shù)中的變量就顯得有些困難,而在Q中就可以使用嵌套的then語句。
本來我還想寫一寫不使用任何輔助模塊的上述代碼,但其實我都很懷疑自己能不能寫對。
另外,你是CoffeeScript的擁泵么?如果是,那你還可以嘗試一下IcedCoffeeScript。IcedCoffeeScript在語言層面上提供了兩個非常有用的關(guān)鍵字: await和defer。基本上所有的流程控制都可以通過這兩個關(guān)鍵字進行改造。不過我本人對IcedCoffeeScript并不熟悉,所以就不在這獻丑了。這里感謝brettof86向我介紹了這一利器,不過我還需要花些時間來熟悉它。
客戶端也許特別慢用Node.js的時候我們可能會變得有點過于理想化了,因此很容易寫出下面這樣的聊天室代碼:
var net = require("net"); var clientList = []; var server = net.createServer(function(c) { //"connection" listener console.log("server connected"); clientList.push(c); c.on("end", function() { console.log("server disconnected"); unpipe_all(c, clientList); remove_from(c, clientList); }); clientList.forEach(function(item){ item.pipe(c); // 注意這 c.pipe(item); // 還有這 }); }); server.listen(8124, function() { //"listening" listener console.log("server bound"); });
我覺得整個結(jié)構(gòu)沒什么大問題,但當(dāng)我們遇上網(wǎng)絡(luò)狀況不好的客戶端時,情況就不大好了。這里的兩個pipe會把數(shù)據(jù)緩存在內(nèi)存中,因此當(dāng)客戶端不能及時接收數(shù)據(jù)時,這些數(shù)據(jù)就會大量滯留在內(nèi)存當(dāng)中。我們往往假設(shè)客戶端的速度還不錯,但其實那都只是假設(shè)!
我想到的一個方法是,用一個中間件來做緩存,當(dāng)數(shù)據(jù)太多時使用文件緩沖,而數(shù)據(jù)不多則用內(nèi)存,如下:
Delegate delegate; clientList.forEach(function(item){ delegate.append(item); // delegate內(nèi)部會有一個與文件關(guān)聯(lián)的緩存 // 如果數(shù)據(jù)太大則把數(shù)據(jù)存入文件 });
如果你有其它的方案來處理這種情況,不妨也分享一下:)
用事件通知完成,而且不要太早大多數(shù)小對象都是同步構(gòu)造的,但對于某些封裝了復(fù)雜操作的對象來說,初始化都有可能是異步的。
如果一個對象需要異步構(gòu)造,那么最好使用事件通知完成。這時你要留意官方文檔 中的一小段話:
This is important in developing APIs where you want to give the user the chance to assign event handlers after an object has been constructed, but before any I/O has occurred.
function MyThing(options) { this.setupOptions(options); process.nextTick(function() { this.startDoingStuff(); }.bind(this)); } var thing = new MyThing(); thing.getReadyForStuff(); // thing.startDoingStuff() gets called now, not before.
典型的解決方案是,在構(gòu)造結(jié)束時用process.nextTick來發(fā)消息:
function SomeTCPServer(options) { var self = this; // 其他可能異步的初始化工作 process.nextTick(function(){ self.emit("ready"); }); } // 其他代碼 var server = new SomeTCPServer(ops); server.on("ready", function when_ready(){ // 其它事情 });
因為用的是process.nextTick,when_ready不會錯過ready事件。
其它建議?我暫時就想起來這么多,因為我自己也不是Node.js的真正專家。不過我還是希望上面的幾條能對新手有所幫助,歡迎大家指出上面的任何錯漏,謝啦。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/77942.html
摘要:中文資料導(dǎo)航官網(wǎng)七牛鏡像深入淺出系列進階必讀中文文檔被誤解的編寫實戰(zhàn)系列熱門模塊排行榜,方便找出你想要的模塊多線程,真正的非阻塞淺析的類利用編寫異步多線程的實例中與的區(qū)別管道拒絕服務(wù)漏洞高級編程業(yè)界新聞看如何評價他們的首次嘗鮮程序員如何說服 node.js中文資料導(dǎo)航 Node.js HomePage Node官網(wǎng)七牛鏡像 Infoq深入淺出Node.js系列(進階必讀) Nod...
摘要:是指可能導(dǎo)致程序終止的非常嚴重的時間。具有最高的級別,旨在關(guān)閉中的日志功能。因此為每一個消息選擇一個合適的日志級別是非常重要的。日志的個小建議將日志訪日代碼塊它能顯著的減少因為字符串拼接而帶來的性能的影響。 前言 首先,這篇文章沒有進行任何的日志功能的詳細介紹,而是對日志提出了幾種最佳實踐。適合對日志記錄有所了解的同學(xué)閱讀。下面是正文: JAVA日志管理既是一門科學(xué),又是一門藝術(shù)。科學(xué)...
摘要:最近剛好有在研究銀聯(lián)云閃付的支付模塊,所以就寫篇總結(jié)分享給大家。很方便的就是,銀聯(lián)云閃付的接入給我們準備了測試模式,就是你并不需要真的有商戶號才能開發(fā),不像微信支付那樣非要有商戶號才能測試開發(fā)。 你好,是我琉憶。最近剛好有在研究銀聯(lián)云閃付的支付模塊,所以就寫篇總結(jié)分享給大家。 這算是第二次接觸支付的東西了,接觸得最多的是接入微信支付,自己也有相關(guān)的總結(jié)文章,可以去segmentfaul...
閱讀 3174·2023-04-25 19:09
閱讀 3885·2021-10-22 09:54
閱讀 1757·2021-09-29 09:35
閱讀 2914·2021-09-08 09:45
閱讀 2256·2021-09-06 15:00
閱讀 2773·2019-08-29 15:32
閱讀 1038·2019-08-28 18:30
閱讀 375·2019-08-26 13:43