閱讀495 返回首頁    go 阿裏雲 go 技術社區[雲棲]


《node.js開發指南》觀後感

最近在當當網上買了一本《node.js開發指南》,從學習node.js到現在看的第一本中文教程,也算獻出了自己處子之身啊,哈哈。前後大約花了4,5個小時通讀了node.js部分,附錄部分隻是略過了,談一下感想把。

1、本書的定位:
就像書中的前言部分所述,確實是針對node.js還未入門的初學者準備的,但是有一個前提,如果之前沒寫過像php等後端的語言讀本書可能有點迷茫。所以本書的定位人群應該是對後端腳本語言有過一定開發經驗,並且熟悉javascript語法的人。

2、本書的組成部分:
個人感覺分為3塊,前麵一大部分是node.js介紹安裝,中間一塊和最後node.js的核心API介紹和熱門模塊,最後是一個簡單的微博web應用,主要介紹了模板和mongodb的增刪改查。個人感覺前麵node.js安裝和介紹有點多,而實際應用有點少。

3、總體感覺:
本書內容很豐富,很多知識麵都談到了,但是不夠深入,真的很適合初學者。API的介紹也不夠詳細,僅僅介紹了幾個主要的,比如cluster模塊的多進程通信、buffer模塊的深度應用事例以及net模塊的TCP/IP服務器都沒有深入。至少是第一本中文的node.js教程,希望大家多多支持啦。

4、個人感覺書中有不妥的地方,列舉幾處,希望作者能夠在改版中參考下,代表個人意見哦,可能說的不對。

A)書中75頁,httprequest.js,期中代碼片如下:

var contents = querystring.stringify({ name: 'byvoid', email: 'byvoid@byvoid.com', address: 'Zijing 2#, Tsinghua University', }); var options = { host: 'www.byvoid.com', path: '/application/node/post.php', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length' : contents.length } };

大家注意這個contents.length,當contents都是英文及半角符號時沒有問題,但是如果有中文,這樣計算 Content-Length 會出現問題,應改為:Buffer.byteLength(contents, 'utf8')
當然這裏作者使用了querystring.stringify 方法,能夠自動將中文轉義,所以不存在這個問題,這裏可能是個小坑,要注意哦

B)書中第115頁,代碼片段如下:

// 讀取 users 集合 db.collection('users', function(err, collection) { if (err) { mongodb.close(); return callback(err); } // 爲 name 屬性添加索引 collection.ensureIndex('name', {unique: true}); // 寫入 user 文檔 collection.insert(user, {safe: true}, function(err, user) { mongodb.close(); callback(err, user); }); });


這邊我感覺是作者的一個失誤,因為這個代碼片段屬於User.prototype.save,是用戶注冊執行的方法。這裏每注冊一個用戶就為集合users建立一次name的唯一索引實在欠妥,應該在app啟動時初始化對數據庫建立索引,並且應該先判斷索引是否已經存在,而不必每次插入數據庫創建一遍索引。

C)同樣是上麵的一段代碼,我們看期中綠色部分
大家注意到了{safe:true}這個設置了吧,作者沒有說明這個{safe:true}的含義,我在這邊簡單介紹下。
1、不加{safe:true}表示我們mongodb客戶端向數據庫拋出這句insert語句後,立刻執行回調函數,而不去關心是否真的插入成功,類似往河裏扔石頭,扔了就告訴媽媽,我扔石頭了。
2、加上{safe:true}表示mongodb數據庫已經成功執行這條insert語句,並且插入完成或者報錯後執行回調函數,類似往河裏扔石頭,看見水花起來了,或者不小心砸到河上的船了,然後告訴媽媽。

D)書中114頁,這樣寫到:
req.flash是express提供的一個奇妙的工具,通過它保存的變量隻會在用戶當前和下次的請求中被訪問... ....
作者如此描述,感覺req.flash很厲害,瞬間讓我產生了好奇,因為當初我寫 rrestjs 框架時借鑒了很多expressjs的源代碼,並沒有發現有req.flash,翻看expressjs3.0的源碼發現沒有req.flash的方法,於是在connect-flash模塊中找到了它,貼下它的源碼:


var format = require('util').format;
... ...
function _flash(type, msg) {
  if (this.session === undefined) throw Error('req.flash() requires sessions');
  var msgs = this.session.flash = this.session.flash || {};
  if (type && msg) {
    // util.format is available in Node.js 0.6+
    if (arguments.length > 2 && format) {
      var args = Array.prototype.slice.call(arguments, 1);
      msg = format.apply(undefined, args);
    }
    return (msgs[type] = msgs[type] || []).push(msg);
  } else if (type) {
    var arr = msgs[type];
    delete msgs[type];
    return arr || [];
  } else {
    this.session.flash = {};
    return msgs;
  }
}

簡單分析下:

如果沒有開啟session功能,則直接拋出異常,也就是說這個req.flash是存放在session裏的,所以並沒有像作者寫的那麼神奇,頓時很失落。1.如果type和msg都傳參了,如果參數長度大於2,則執行format函數將msg字符串處理一下。然後往msgs[type]數組中插入msg字符串。
2.如果隻有一個參數,則刪除這個msgs[type],返回改數組,這裏就是作者說的一次性的關鍵。
3.清空msgs對象,返回整個msgs對象。
其實這個函數還是很巧妙的,保證了req.flash的一次性使用,節能環保,嗬嗬,當然沒有作者說的那樣神奇啦。

E)書中第124頁,代碼片段如下:

function Post(username, post, time) { this.user = username; this.post = post; if (time) { this.time = time; } else { this.time = new Date(); } };

作者直接使用 new Date()方法存放了時間。在數據庫存放時間格式上一直很有爭議,我個人一直是存時間戳的,原因有如下幾個:
1.存儲空間的節約,時間戳要比格林威治時間存儲空間更小
2.便於比較和排序
3.如果有其他語言比如php也要共享這部分數據,隻需要把js生成的時間戳除以1000既可以轉化為時間格式了,php的time()返回是以秒為單位的時間戳。
所以建議這邊作者改為 Date.now()

最後當然是廣告時間了:
看到作者為了判斷除了首頁,其他頁麵都需要用戶登錄寫了如下代碼片段:

app.get('/reg', checkNotLogin);

... ...

app.post('/reg', checkNotLogin);

... ...

app.post('/login', checkNotLogin);

... ...

app.get('/logout', checkLogin);

... ...

app.post('/post', checkLogin);

... ...

如果應用的頁麵越來越多,這樣的代碼會越來越來長,如果你使用了 rrestjs 框架,情況就完全不一樣了,我們看下使用rrestjs框架的實現

我們看下代碼片段:

var http = require('http'), rrest = require('rrest'), server = http.createServer(rrest(function (req, res) { var noCheckUrl = ['index', 'other'];//rrestjs會默認把'/'認為'/index' if(!~req.path[0].indexOf(noCheckUrl) && !isLogin(req, res)) return res.redirect('/login') //normal routes })).listen(rrest.config.listenPort);

隻需要在入口處判斷哪些請求url需要驗證登錄即可全部搞定,無需重複的代碼拷貝。
rrestjs框架地址:https://www.rrestjs.com/

最後希望大家多多支持中文的node.js教程,都去買正版書籍把,《node.js開發指南》真是一本難得中文node.js好教材!推薦一個


最後要給作者提一下啊,書中第6頁,node.js和php+nginx對比測試的數據我的名字打錯 ,應該是snoopyxdy,而不是snoopyxd。而且測試的數據沒有把硬件以及node,linux,php版本號以及網絡環境等相關因素寫進去,不夠嚴謹。

另外關於nginx+node.js的小建議:
之前我曾經開4個node.js綁定4個CPU然後nginx開4個進程,綁定4個CPU,結果悲劇了,壓測一直卡死,原來是node.js和nginx搶CPU造成的,後來楚漢分界,nginx用前2個CPU,而node.js拿後兩個cpu。另外nginx也像汽車一樣,要先熱車,重啟後先隨便壓測幾次,然後過一會水溫就上來了,就可以踩油門了,哈哈。

最後更新:2017-04-03 05:39:32

  上一篇:go graph driver-device mapper-04libdevmapper基本操作
  下一篇:go C# 動態加載Dll