iT邦幫忙

DAY 19
7

node.js伺服器實戰系列 第 19

node.js伺服器實戰(19) - 靜態分析

  • 分享至 

  • xImage
  •  

靜態分析可以從另外一個角度來檢查程式碼的問題,例如未宣告的變數,比較不好的撰寫風格(這個是見仁見智)等等。這樣可以讓程式更健全,也更好維護。(有些問題單靠測試恐怕很難抓到)
工具

我知道這方面最有名的工具大概有:

  1. Douglas Crockford的JSLint,原始碼放在https://github.com/douglascrockford/JSLint,並且還在持續維護
  2. Google Closure系列工具:Google Closure Linter

JSLint內建了一個用Javascript寫的Javascript Parser,並且用Parser來分析Javascript原始碼,然後指出在程式碼中找到的問題。(如果你有看過「Beautiful Code」,裡面有一章是Crockford介紹遞迴下降Parser,並且寫了一個精簡版。正式版就用在JSLint以及ADSafe中。另一個有名的Javascript Parser in Javascript是Brendan Eich的Narcissus。)

Closure Linter使用了不同的技術,基本上他是一個使用Regular Expression的Tokenizer,使用的語言是Python。(看起來並不會做出AST)

看起來JSLint比較合胃口,也比較多人用,接下來就看看在node.js環境有沒有相關的工具。

查詢了一下,目前有一個套件叫做node-jslint,裡面包裝了JSLint(都是用Javascript寫的),就拿來試試看吧。

實做

看起來安裝很簡單,只要

npm install -g jslint

就會安裝好。安裝完畢後,以Windows為例,會在node\bin目錄(也就是node.exe所在的目錄)會產生一個jslint.cmd。之後只要執行:

jslint app.js

就可以跑出結果。

測試

接下來,就實際針對lib目錄中的伺服器核心程式做一下檢查,先看一下evolve.js有怎樣的問題:

lib\evolve.js
/*jslint node: true, es5: true */
  1 9,42: Confusing use of '++'.
    console.log(process.pid + '::' + ++count + ': ' + process.memoryUsage().heapUsed);

在字串串接中加上遞增容易讓人誤解,所以改一下程式吧...把++count改成(++count)看看...OK,沒問題了。接下來測試cache.js:

lib\evolve.js
/*jslint node: true, es5: true */
No errors found.

看起來沒有問題。接下來再看看router.js:

lib\router.js
/*jslint node: true, es5: true */
  1 12,31: Expected '{' and instead saw 'path'.
    if(path.indexOf('/')!==0) path = '/' + path;
  2 20,31: Expected '{' and instead saw 'path'.
    if(path.indexOf('/')!==0) path = '/' + path;
  3 23,22: Expected '{' and instead saw 'a'.
    if(!a[path]) a[path] = {};
  4 29,30: Expected '{' and instead saw 'dir'.
    if(dir.indexOf('/')!==0) dir = '/' + dir;
  5 37,11: 'a' is already defined.
    var a = cache.get(host, 'fs');
  6 39,13: Move 'var' declarations to the top of the function.
    for(var i in a) {
  7 39,13: Stopping.  (58% scanned).

看起來問題太多,沒跑完XD,先照他的建議改一改。

lib\router.js
/*jslint node: true, es5: true */
  1 48,9: The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
    for(i in a) {
  2 62,17: Expected '===' and instead saw '=='.
    if(typeof a == 'undefined' || typeof b == 'undefined') {
  3 62,44: Expected '===' and instead saw '=='.
    if(typeof a == 'undefined' || typeof b == 'undefined') {

還有問題阿Orz...繼續改到好...接下來看一看tools.js:

lib\tools.js
/*jslint node: true, es5: true */
  1 1,25: Expected ';' and instead saw 'fs'.
    var url = require('url')
  2 2,23: Expected ';' and instead saw ','.
    fs = require('fs'),
  3 2,23: Expected an identifier and instead saw ','.
    fs = require('fs'),
  4 2,23: Stopping.  (1% scanned).

...只scan了1%Orz...不過看了一下程式,第一行的結尾就忘了加comma...靠,改一下:

lib\tools.js
/*jslint node: true, es5: true */
  1 17,66: Expected ';' and instead saw '}'.
    process.nextTick(function(){cb(true, respath)});
  2 28,78: Expected ';' and instead saw '}'.
    process.nextTick(function(){cb(true, tmp)});
......
  9 93,87: Expected ';' and instead saw '}'.
    process.nextTick(function(){tools.getRes(handle.result, conf.dirindex, cb)});
 10 98,4: Mixed spaces and tabs.
    var tmp1 = cookie_str.split(/[;,] */g),
 11 99,4: Mixed spaces and tabs.
    tmp2,
 12 110,4: Mixed spaces and tabs.
    if(request['headers']['Cookie']) {
 13 110,16: ['headers'] is better written in dot notation.
    if(request['headers']['Cookie']) {
 14 110,27: ['Cookie'] is better written in dot notation.
    if(request['headers']['Cookie']) {
 15 111,21: ['cookie'] is better written in dot notation.
    request['cookie'] = tools.cookieParser(request['headers']['Cookie']);
 16 111,60: ['headers'] is better written in dot notation.
    request['cookie'] = tools.cookieParser(request['headers']['Cookie']);
 17 111,71: ['Cookie'] is better written in dot notation.
    request['cookie'] = tools.cookieParser(request['headers']['Cookie']);
 18 112,4: Mixed spaces and tabs.
    } else {
 19 113,21: ['cookie'] is better written in dot notation.
    request['cookie'] = {};

問題多到無言,只好繼續改到沒有問題為止。

JSLint抓到的問題,其實主要是程式風格的問題,但是也能抓到細微的錯誤,像是連續變數宣告,變數後沒有有加上comma...單元及整合測試能通過是運氣好,因為V8夠聰明,如果是瀏覽器端的程式就很難說了。從這裡也可以看到JSLint的用處。

今天的範例檔(fillano-evolve-v0.0.14-0-g6928eac.zip),目前版本是v0.0.14。(這是把上述問題修改過的版本,可以跟前一個版本比較一下)

相關文章


上一篇
Node.js伺服器實戰(18) - 覆蓋率測試
下一篇
node.js伺服器實戰(20) - 伺服器架構設計
系列文
node.js伺服器實戰33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
SunAllen
iT邦研究生 1 級 ‧ 2011-10-29 01:36:53

之前好忙,最近比較好了。忙忙快寫筆記暈

我要留言

立即登入留言