I have been searching for a useful JavaScript Parser for Jscex. Previously I used Narcissus and wrote related articles. Unfortunately, Narcissus uses the extension of SpiderMonkey, so it is not implemented using ECMAScript 3 and cannot be used in IE 8 or other browsers. Currently, Jscex uses the earlier version of Narcissus in NarrativeJS, but I do not like the AST structure output. I also found some bugs in advanced functions, which may seem boring, the new version of Narcissus must be rewritten. Recently I came into contact with UglifyJS and found that its parser is quite good and its performance is much higher than that of Narcissus. I would like to introduce it to you here.
UglifyJS is a JavaScript compressed file, which is far behind Google Closure Compiler.For modern JavaScript compressors, it is far from enough to simply remove spaces and compress local variables. At the same time, you must understand the semantics of the Code, replace it with a smaller form (there are many descriptions on the Uglify description page ). This obviously requires a JavaScript parser. UglifyJS is developed based on NodeJS, but it can run on various JavaScript Engines/platforms that support CommonJS module systems. If you do not have CommonJS, you only need to remove the exports-related code.
The function of the JavaScript parser is to break JavaScript code into AST, and then use AST to do many interesting things.The same AST can have different manifestations in the memory. For example, I mentioned earlier that I do not like the old version of Narcissus currently used by Jscex, one important reason is that its AST structure is unfriendly (the latest Narcissus is good ). In addition, although it provides some advanced functions, such as marking the position of each element in the source code, in this way, the user can directly obtain the corresponding source code based on the getSource method-unfortunately, this function has a bug, which forces me to traverse the complete AST.
UglifyJS JavaScript word divider and parser are stored in the source code parse-js.js file, transplanted to the parse-js project, the latter is a class library implemented with Common Lisp. Now you can guess the representation of the output AST. That's right, it's a "table", represented by JavaScript, that is, a number of arrays. I wrote some simple code to format and output it. Here you can try the UglifyJS parser. This output is simple, but it is enough for Jscex.
Use
Open the parse-js.js file and you will see code like this:
- /* -----[ Tokenizer (constants) ]----- */
-
- var KEYWORDS = array_to_hash([
- ...
- ]);
-
- var RESERVED_WORDS = array_to_hash([
- ...
- ]);
-
- ...
-
- function parse($TEXT, exigent_mode, embed_tokens) {
- ...
- }
-
- /* -----[ Exports ]----- */
-
- exports.tokenizer = tokenizer;
- exports.parse = parse;
- exports.slice = slice;
- exports.curry = curry;
- exports.member = member;
- exports.array_to_hash = array_to_hash;
- exports.PRECEDENCE = PRECEDENCE;
- exports.KEYWORDS_ATOM = KEYWORDS_ATOM;
- exports.RESERVED_WORDS = RESERVED_WORDS;
- exports.KEYWORDS = KEYWORDS;
- exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
- exports.OPERATORS = OPERATORS;
- exports.is_alphanumeric_char = is_alphanumeric_char;
- exports.set_logger = function(logger) {
- warn = logger;
- };
UglifyJS is written based on the CommonJS module mechanism. This file is actually a module and its external method is exposed through exports. If we introduce it into the browser as a common JavaScript file, the exception "export undefined" is clearly reported. Theoretically, if you define an exports object and even remove Code related to exports, you can use the parse method normally. But there is also a serious problem, that is, the "pollution" of the root object is too serious. For example, all the functions in the browser are defined on the window, introduce some other class libraries, causing a high possibility of conflict.
Therefore, we must make some modifications to the code. Fortunately, it is very easy to solve this kind of "Scope" problem in JavaScript, for example I 've surrounded the code of the parse-js.js like this:
- var UglifyJS = {};
-
- (function (exports) {
-
- /* original code here */
-
- })(UglifyJS);
In this way, the scope problem is solved. Now we can access the KEYWORDS set on the UglifyJS object and members such as parse.
Performance
Then let's talk about performance. JavaScript has always been regarded as a language with low execution efficiency-this is actually a wrong idea. In fact, in terms of language design, JavaScript is faster than Python and Ruby, but for historical reasons, browsers do not pay much attention to it. But now the situation has changed for a long time. Under V8's leadership, the execution speed of modern JavaScript Engines has exceeded the current fastest Python and Ruby implementations. Let's talk about the performance of UglifyJS parser and Narcissus in various browsers.
Test page in this http://files.zhaojie.me/demos/js-parsers/benchmark.html), you can also try it on your own, the test scenario is to use both to parse the implementation of ten Narcissus-about 1500 lines of uncompressed JavaScript code (it is worth mentioning that, I tried a lot of compressed code, such as jquery-min.js, which can be parsed normally with UgilifyJS, but Narcissus fails to parse ). I used two standard working machines configured by the company and tested six browsers for IE, Chrome, and Firefox. In each browser, I run the test multiple times to get the result of high deviation and take the midstream value. Unfortunately, due to the limited conditions, the operating systems of the two machines are different. Although I don't think it will affect the results, if you are honest enough, you may wish to evaluate it on your own.
First, I tested Chrome 10, FireFox 3, and IE9 in Win 7. The results are as follows:
For UglifyJS, Chrome 10 has the best performance. IE 9 is a little slower than IE 9, while Firefox 3 consumes several times of the previous two. For Narcissus, it is the best performance of IE 9, which is only 1/5 of Chrome 10 and is more advanced than Firefox 3. Interestingly, Chrome 10 and Firefox 3 both consume about a dozen times, while IE 9 does not.
The result is chrome 12, Firefox 4, and IE 8 in Windows XP:
For UglifyJS, the performance of Chromium 12 is still eye-catching, better than Firefox 4, but the use of Narcissus is the opposite. We can also see that IE 8 lags behind this era in terms of JavaScript engine performance, but it is similar to IE 9, Firefox 4 (and Safari later, that is, the time consumption between UglifyJS and Narcissus is not much different.
For ease of observation, I put the results of the two tests together (except for the informal version of Chromium 12 ):
In general, Chrome 10, IE 9, and Firefox 4 are the first army. IE 9 is less than Chrome 10 in UglifyJS, but has obvious advantages in Narcissus; Chrome 10 is the best in UglifyJS, But it lags behind in Narcissus; although Firefox 4 is not "the best", the gap is not big. As for IE 8 and Firefox 3, JavaScript Execution efficiency is indeed lagging behind this era. It must be admitted that today's browser wars have indeed greatly improved the quality of all parties.
In addition, I tested Chrome 10, Firefox 3, and Safari 5 on iMac, and listed the results here:
Although the performance of the browser varies, the performance of the UglifyJS parser is indeed higher than that of Narcissus. Therefore, I plan to replace the Narcissus currently used in Jscex with UglifyJS in the next few days.
Summary
As front-end development and broad cirpt become popular, more and more people are beginning to use JavaScript to do interesting things. I do not like many of the so-called front-end practices nowadays. They are entangled in a large number of hack and the performance of various browsers, and even some specific writing in JavaScript has a higher performance. For example, there is a message saying, for string join operations, the performance of a + = B is higher than that of a = a + B (or vice versa ). In my opinion, these things are the most useless. What if I know? With the upgrading of browsers, these "Experiences" will be useless in an instant.
This is why I like JavaScript, but I am reluctant to do front-end development, especially HTML and CSS. Similarly, browsers like IE 6 must be wiped out in my eyes.
Link: http://blog.zhaojie.me/2011/04/uglifyjs-has-a-good-javascript-parser.html