zoukankan      html  css  js  c++  java
  • jslint


    今天要介绍的Douban-JSLint,就是为规范定制的工具。它是nodeJS版的,对比用Java+Rhino的使用方式,方便多了,也易于安装和升级。安装方法:

    第1步,当然要先有nodeJS环境(安装参考:https://github.com/joyent/node/wiki/Installation)
    第2步,推荐用npm(nodeJS包管理工具)安装: npm install http://github.com/kejun/Douban-JSLint/tarball/master

    或者,也可以先将源码clone下来(如果装了git),进入目录,再用 npm install . 完成安装。

    这样就装完了。使用时:

    。。。


    Running jslint from the commandline using spidermonkey

    A lot of people are aware of the JSLint javascript syntax parser, and if they're not, they should be! JSLint, created by Mr. Douglas Crockford is a wonderful utility that can save you a lot of grief when you're writing javascript. Why? Well, because javascript is designed to be run behind the scenes by your web browser. In order to keep the experience as seamless as possible for the end-user, the default method of error reporting is... nothing. This makes a lot of sense, actually, because javascript needs to be given all sorts of leeway so that it can degrade properly as well as keep the user from becoming confused. Hence, in order to get at your javascript, you need to install something like firebug, which integrates with your browser itself.

    Why JSLint is a good idea.

    Firebug is nice enough, but it's geared more towards step-through and data inspection, and it has somewhat rudimentary support for javascript syntax checking and, it really helps to catch these sorts of things before they get to the browser.The trick is, of course, that javascript is "flexible" to say the least, and some of these errors can be quite pernicious and hard to catch. For instance, this causes problems for some browsers:

    var myPerson = {
        name: "Andy Walker",
        init: function() {
        	alert('YAWN!');
        },
        Height: '180cm',
        Weight: '99.5kg',
    };
    

    Whereas this is perfectly fine:

    var myPerson = {
        name: "Andy Walker",
        init: function() {
        	alert('YAWN!');
        },
        Height: '180cm',
        Weight: '99.5kg'
    };
    

    The problem? That final comma in the object literal. Now, try finding that in 1500 lines of code with nothing to go on.

    And then there's for/in which, while a very useful tool, is fraught with danger. Here's an example about two seconds of searching turned up online:

    // function to initialise the login stuff
    function initLogin () {
    	var login = ["login-username", "login-password"];
    	for ( var i in login ) {
    		alert(login[i]);
    	}
    }
    

    This code, the poor programmer complained, was outputting the first two items "just fine", but that it suddenly "starts going mad and alerts a whole load of random functions". Oh noes!

    Ignoring for a moment that it is utterly retarded to debug this way, what could have been happening? Well, it turns out that another programmer had been including a framework into each page which, in turn, was adding inheritance he wasn't aware of. Easy enough to figure out if you know what you're doing and IF you have a visual cue like this that tells you you're getting more than you expected! [for more information on for/in check out this page].

    Gosh, wouldn't it be nice to spot some of this stuff ahead of time? By running JSLint on all of our javascript files as part of our development process, we can find these nasty bugs before they start! A flexible way to do this would be to use a commandline utilty that can take a file as input and then output any problems it finds. Unfortunately, JSLint is alsowritten in javascript, which makes it kind of difficult to leverage from the commandline.

    How to do it.

    There are a few different methods to run Javascript at the commandline, each of which has their own little quirks, espcially since JSLint needs to somehow access the file it's going to parse, and javascript wasn't really designed to be a console scripting language.

    So, what are our options? Well, it turns out there are four of them, each with their own problems:

    Rhino

    Rhino is, like the site says: "an open-source implementation of JavaScript written entirely in Java." Mr Crockford is aware of this option, and has thoughtfully provided a version of JSLint that can be run through Rhino directly from the commandline. Initially, this seems like a pretty good solution, because Rhino is written in Java, this also makes it portable. Unfortunately, this is also a drawback. As dom (who hates software) has noted, it's excessive to fire up the JVM each time we want to scan a javascript file, and Rhino isn't really intended to run quick one-off scripts like this. It's more for embedding the power and flexibility of jacascript into java applications. Imagine extending this solution to a case where you want to scan through 50-100 or more files as part of a nightly smoke-test or something, and it starts to look less and less promising.

    WSH

    WSH, or the Windows Script Host, is actually a pretty spiffy utility that lets you run a number of different types of scripting languages from the commandline and can help you automate various tasks on your Windows system. Unfortunately, this leaves mac and *nix users out in the cold, and I don't think Microsoft is going to port it any time soon (though there is aversion of JSLint for WSH).

    NJS

    NJS, according to its sourceforge site is "an independent implementation of the JavaScript language developed by Netscape and standardized by ECMA." Hey, neat! This sounds like a great option! Let's just click on the site and downlo—oh. Shit. Looks like the site is down. Looks like it's been down for a long time. Looks like this isn't an option after all.

    Spidermonkey

    Spidermonkey, according to the terse little blurb on its site, is "the code-name for the Mozilla's C implementation of JavaScript.". Well, this seems promising. This is the engine they use in the browser, after all, so it has to be as fast as possible. So... that's nice. And, it looks like there are versions for linuxBSD, and even Windows! (sorta, but you could always build your binary or use WSH).

    So, okay, it's fast and portable, what's the catch? Well, the catch is that spidermonkey doesn't have any kind of file-reading enabled by default. The Rhino version of JSLint leverages Rhino's readFile() extension to javascript, in order to parse the file into a variable, but Spidermonkey's corresponding File type isn't enabled in most distributions (certainly not the standard linux one) because it can potentially cause security problems and isn't well tested. So, Spidermonkey works, in theory, but it has no facility to read files from the disk, so it seems useless to us. Is there anything that can be done?

    Well, there have been a few attempts to get around this, but they involve weirdness in passing the file into anotherjavascript script and they also require you to parse html output and, in general, can be frustrating, so I thought I'd try and find a better way.

    Spidermonkey to the rescue!

    As I mentioned, Spidermonkey doesn't support the File object by default. They even have a big red exclamation point that says why. Sure, I could compile it in (and I tried), but I quickly learned that this would require an entire assload of extra functionality pulled in from the NSPR, which causes bloat and is sort of the problem with the Rhino solution (although admittedly less so). So, what to do?

    Well, it turns out that, while Spidermonkey does not support the File object, it DOES support reading in from stdin withreadline(), which is a start. The problem with this initially is that readline() is intended for interactive input, meaning prompted and one-line-at-a-time. So, while this provides us with a method to get something into the interpreter, there's no easy way to tell when the input is complete or to simply say "read this entire file X into this variable Y. The way I discovered to get around this is to use a simple loop like this:

    var input="";
    var line="";
    while (line=readline()){
        input += line;
        input += "\n";
    }
    print (input);
    

    Which works... sort of. Sure, I have to add a newline to replace the newline that's chopped off by the shell interaction, but it reads the file in. Just not all the way. The problem is that the test (line=readline()) fails when readline is nothing.. which happens the first time a blank line comes out of the file, so when I run:

    # js testread.js < myfile

    or

    # cat myfile | js testread

    I only get the first few lines of my file up until the newline.

    The Solution

    To solve this I had to figure out some way to read the blank lines in the file and still terminate when the file was done. The way I figured it out is actually really simple: I just wait until readline() returns nothing 10 times in a row:

    var input="";
    var line="";
    var blankcount="0";
    while (blankcount < 10){
    	line=readline();
    
    	if (line=="")
    	    blankcount++;
    	else
    	    blankcount=0;
    	if (line=="END") break;
    	input += line;
    	input += "\n";
    }
    input = input.substring(0, input.length-blankcount);
    

    The number 10 itself is rather arbitrary and it could be anything, really, but I wanted a number that was high enough that it probably wouldn't occur in any kind of valid context, yet small enough so that it would be almost instantaneous to parse. I could probably even have gotten away with 5, but I could conceivably see some over-zealous newbie separating blocks of code with this number of newlines, so 10 seemed like a good number.

    This plays off of the fact that readline() will just continuously return nothing when it's reading from an empty pipe (like if you pipe to it or redirect to it as above). I added in the if (line=="END") break; so that you could conceivably run it directly from the commandline and then type Javascript into it or paste to it and then tell it that you were done directly, rather than hitting enter 10 times.

    What does this buy you?

    Flexibility

    A nifty side effect of this is that you can use it in a couple of different ways directly from the commandline. Also, Spidermonkey (unlike Rhino) can be used as a script interpreter, so you can just take the modified JSLint and slap#!/usr/bin/js on the beginning, make it executable, and run it or pipe things to it directly, just like any other script.

    Speed

    Turns out, Spidermonkey isn't just faster than Rhino, it's a lot faster (at least to start up). Let's try it on a 556-line javascript file I have:

    $ time rhino ~/bin/jslint-rhino.js MyFile.js
    jslint: No problems found in MyFile.js
    
    real    0m2.143s
    user    0m5.292s
    sys     0m0.140s
    
    $ time cat MyFile.js | ~/bin/jslint
    jslint: No problems found.
    
    real    0m0.511s
    user    0m0.500s
    sys	0m0.016s
    
    $
    

    Which is pretty impressive, but let's simulate it with 50 files, as if we were scanning an entire tree as part of a build acceptance test or something:

    $ time for i in `seq 1 50` ; do rhino ~/bin/jslint-rhino.js MyFile.js ; done
    jslint: No problems found in MyFile.js
    jslint: No problems found in MyFile.js
    jslint: No problems found in MyFile.js
    .
    .
    .
    jslint: No problems found in MyFile.js
    
    real	1m50.899s
    user	4m54.166s
    sys	0m6.184s
    
    $ time for i in `seq 1 50` ; do cat MyFile.js | ~/bin/jslint ; done
    jslint: No problems found.
    jslint: No problems found.
    jslint: No problems found.
    .
    .
    .
    jslint: No problems found.
    
    real	0m25.727s
    user	0m25.330s
    sys	0m0.456s
    
    $
    

    Gah! Almost 20 times as long!

    Of course, benchmarking is evil and unrealistic, but when the spread is this big, there's usually something to it.

    Get it

    So, that's enough of my little adventure. Here's the modified version of JSLint that I came up with (which is really just a small hack, but it works and it's faster than the accepted alternative and doesn't require you to install any bulky frameworks to get your job done). 

    (spidermonkey hack edition)

    Use it

    If you're on Linux, you should be able to just apt-get spidermonkey-bin or your eqivalent package and then chmod it, and away you go! If you intend on using this in a non-unix environment or don't want to use the nifty spidermonkey-as-an-interpeter foo, just remove the first line, and remember that this utility, as it's written, is intended to be used as a pipe or redirect target.

    Improve it

    It could certainly use some polishing and tweaking to make it behave more like a good console app should. My next step is to wrap it in a simple perl script that maps the different options to commandline arguments and passes them into the script. This will enable more fine-tuned control over what JSLint checks for, as well as making it behave more like a modern console app and less like a pager. Expect those soon, but if you beat me to it, feel free to email!

    Enjoy!



    Comments?

    Warning: mysql_connect() [function.mysql-connect]: Unknown MySQL server host 'mysql.whereisandy.com' (1) in/home/walkeraj/whereisandy.com/code/jslint/comments/comments_show.php on line 33
    Connection Error: Unknown MySQL server host 'mysql.whereisandy.com' (1)

    在Ubuntu下编译的,很简单。 

    先 
    引用
    svn checkout http://v8.googlecode.com/svn/trunk/ v8-read-only

    下载source 

    然后 
    引用
    sudo apt-get install scons


    在 v8-read-only 下面运行 
    引用
    scons sample=shell mode=release library=shared snapshot=on


    编译完成之后,把 libv8.so 拷到 /usr/lib 下面 

    运行 ./shell 试试 

    到 http://v8.googlecode.com/files/benchmarks-v1.zip 下载了个benchmark包,运行了下 

    引用
    $ ./shell run.js 
    Richards: 1466 
    DeltaBlue: 1472 
    Crypto: 911 
    RayTrace: 737 
    EarleyBoyer: 1417 
    ---- 
    Score: 1155


    再试试用spidermonkey引擎来跑 
    引用
    sudo apt-get install spidermonkey-bin

    引用

    $ js ./run.js 
    Richards: 81 
    DeltaBlue: 81 
    Crypto: 89 
    RayTrace: 96 
    EarleyBoyer: 97 
    ---- 
    Score: 89


    Google的Benchmark例子太欺负人了。。。 

    然后是传说中的Rhino 
    引用

    $ java -server -jar js.jar ./run.jsRichards: 2 
    DeltaBlue: 54 
    Crypto: 65 
    RayTrace: 144 
    EarleyBoyer: 130 
    ---- 
    Score: 43


    我快要哭了 

    补充,编译传说中的TraceMonkey: 

    引用
    hg clone http://hg.mozilla.org/tracemonkey/ 
    cd tracemonkey/js/src 
    make -f Makefile.ref BUILD_OPT=1


    运行: 
    引用
    Linux_All_OPT.OBJ/js -j

    其中-j指开启jit 

    目前这个JIT还很不稳定,开启之后运行上面的benchmark,会出错 

    引用

    Error during execution: queueCount = 0, holdCount = 0. 
    Error during execution: queueCount = 0, holdCount = 0. 
    ...... 
    Error during execution: queueCount = 0, holdCount = 0. 
    Error during execution: queueCount = 0, holdCount = 0. 
    Richards: 17003 
    DeltaBlue: 118 
    Crypto: 56 
    raytrace.js:2768: InternalError: too much recursion


    若不使用-j参数,则很正常,比SpiderMonkey快一些: 
    引用

    Richards: 139 
    DeltaBlue: 160 
    Crypto: 112 
    RayTrace: 177 
    EarleyBoyer: 274 
    ---- 
    Score: 165


    分享到:  
    评论
    2 楼 Arbow 2008-09-20  
    对 fasta 这个例子,lua快了一倍

    1,000,000 Loops:

    引用

    time lua fasta.lua 1000000 > /dev/null 

    real 0m5.870s
    user 0m5.864s
    sys 0m0.004s

    引用

    time ../shell fasta.js > /dev/null 

    real 0m11.562s
    user 0m11.553s
    sys 0m0.004s
    1 楼 Arbow 2008-09-20  


    SpiderMonkey在对阵传说中‘最快脚本’的Lua时,力不从心,派V8出马,我简单测了一下 partial-sums 这个例子的代码,100000 loop时,两者基本持平:

    V8:
    引用
    time ../shell partialsums_v8.js
    3.000000000 (2/3)^k
    630.996758662 k^-0.5
    0.999990000 1/k(k+1)
    30.314520870 Flint Hills
    42.995159874 Cookson Hills
    12.090146130 Harmonic
    1.644924067 Riemann Zeta
    0.693142181 Alternating Harmonic
    0.785395663 Gregory

    real 0m0.252s
    user 0m0.248s
    sys 0m0.004s


    注:因为v8不支持 arguments[0] ,所以我硬编码写成 var n = 100000; 了

    Lua:
    引用
    time lua partialsums.lua 100000
    3.000000000 (2/3)^k
    630.996758662 k^-0.5
    0.999990000 1/k(k+1)
    30.314520870 Flint Hills
    42.995159874 Cookson Hills
    12.090146130 Harmonic
    1.644924067 Riemann Zeta
    0.693142181 Alternating Harmonic
    0.785395663 Gregory

    real 0m0.549s
    user 0m0.212s
    sys 0m0.000s

  • 相关阅读:
    Appium+python自动化17-启动iOS模拟器APP源码案例
    Pycharm上python和unittest两种姿势傻傻分不清楚
    jenkins显示html样式问题的几种解决方案总结
    Appium+python自动化16-appium1.6在mac上环境搭建启动ios模拟器上Safari浏览器
    selenium+python在mac环境上的搭建
    python+requests接口自动化完整项目设计源码
    Appium+python自动化15-在Mac上环境搭建
    git使用教程2-更新github上代码
    git使用教程1-本地代码上传到github
    针对初学者的A*算法入门详解(附带Java源码)
  • 原文地址:https://www.cnblogs.com/lexus/p/2209586.html
Copyright © 2011-2022 走看看