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需要驗證登錄即可全部搞定,無需重複的代碼拷貝。
最後希望大家多多支持中文的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也像汽車一樣,要先熱車,重啟後先隨便壓測幾次,然後過一會水溫就上來了,就可以踩油門了,哈哈。