文档章节

在nodejs 0.10开启ECMAScript 6任督二脉

tulayang
 tulayang
发布于 2015/01/03 22:02
字数 1672
阅读 126
收藏 0

担心ECMAScript 6来的太晚? 不需要! 现在在nodejs 0.10开启ECMAScript 6任督二脉。

首先,我们需要一个ECMAScript 6 -> ECMAScript5的编译器,目前非常之多。这里推荐Google出品的***traceur-compiler***。

这里有一个编译器列表: es6-tools

原理

使用这些编译器,会帮助你把现在用ECMAScript 6语法编写的javascript文件,编译生成ECMAScript 5语法的静态文件。

如果你是coffeescript的使用者,那就很熟悉这种方式,类似coffeescript语法编译成javascript文件。

因为是静态文件,所以不会存在运行时再次编译的性能问题。

另外,也提供了运行时编译,帮助你直接测试ECMAScript 6语法编写的文件。

traceur-compiler 使用入门

首先我想说,需求决定了技术的需要。因为一个项目的复杂度,我急于需要yield 和生成器来简化异步判断。因为对express和koa那种java式的纯面向对象深深的反感之久,(对JAVA C++ 和纯面向对象的批判,已经是卡内基·梅隆大学"反模块化的又是反并行的"的家常便饭),我在长久的积累中,短时间编写出了*ROCORE**,并迅速测试优化,迭代进了0.2.17版本(事实上我现在使用的版本又有了新的改变,一个完全采用ECMAScript 6语法beta的0.3.1版本)。*

为了能够迅速兼容nodejs 0.10,我找到了6to5, traceur-compiler,并选择了traceur-compiler作为编译器。

  1. 安装

    npm install -g traceur

  2. 编写ECMAScript 6语法的文件

编写你的ECMAScript 6文件,例如ec6.js文件:

    // ec6.js

    let a = 1;
    
    function* g() {
        yield 100;
        console.log(a + 100);
    }
    
    var it = g();
    it.next();
    it.next();  
  1. 编译生成ECMAScript 5语法的文件

使用traceur-compiler编译文件,生成ECMAScript文件,比如叫做ec5.js$ traceur ec6.js --out ec5.js --modules=commonjs

打开得到的ec5.js文件,你会看到如下的代码:   "use strict"; var $__0 = $traceurRuntime.initGeneratorFunction(g); var __moduleName = "tt.js"; var a = 1; function g() { return $traceurRuntime.createGeneratorInstance(function($ctx) { while (true) switch ($ctx.state) { case 0: $ctx.state = 2; return 100; case 2: $ctx.maybeThrow(); $ctx.state = 4; break; case 4: console.log(a + 100); $ctx.state = -2; break; default: return $ctx.end(); } }, $__0, this); } var it = g(); it.next(); it.next();

  1. 运行生成的ECMAScript 5文件

    除了全局安装,你还需要另外复制一份,放到你的项目node_modules中,作为项目依赖。模块名是traceur。

    要运行这个ec5.js文件,还需要引入traceur模块。在文件上部,加上

     require('traceur');
    

    然后保存。运行 $ node ec5.js

    OK,输出101. 现在在nodejs 0.10中,能够良好的运行这个文件。

  2. 总结一下过程

    编写ECMAScript 6文件 -> 编译,生成ECMAScript 5文件 -> 修改ECMAScript 5文件,在最上边加入**require('traceur')**保存 -> 运行ECMAScript 5文件。

    在实际使用时,只需要在app.js(或者server.js)主文件中加入**require('traceur')**既可以。

批量编译

我们的项目文件可是有大量的文件,总不能一个一个动手编译吧?!OK。这里有一个批量编译的脚本程序,复制然后保存到一个js文件里,设置要编译的主目录和要输出的目标目录,ta会把主目录的所有js文件编译到目标目录,并且支持递归内部文件,非js文件被原样不变的复制到目标目录。

另外,建议只编译复制lib目录中的文件,其他目录的文件手动复制到目标目录。

// compile.js

var traceur = require('traceur');
var fs = require('fs');
var path = require('path');
var PATH_SOURCE = '/home/king/box-fork/dist';
var PATH_TARGET = '/home/king/box-fork-compile';

function readSync(paths, i, f) {
    if (i >= 0 && i < paths.length) {
        var stats = fs.statSync(paths[i]);
        if (stats.isFile()) {
            f('file', paths[i]);
            return readSync(paths, ++i, f);
        } else if (stats.isDirectory()) {
            var newPaths = fs.readdirSync(paths[i]).map(function (pathname) {
                return path.join(paths[i], pathname);
            });
            f('directory', paths[i]);
            return readSync(paths.slice(0, i).concat(newPaths, 
                                                     paths.slice(i + 1)), 
                            i, f);
        } else {
            return readSync(paths.slice(0, i).concat(paths.slice(i + 1)), 
                            i, f);
        }
    } else {
        return paths;
    }
}

readSync([PATH_SOURCE], 0, function (type, pathname) {
    var newPath = path.join(PATH_TARGET, pathname.replace(new RegExp('^' + source.replace(/\//g,'\/').replace(/\\/g,'\\')), ''));
    if (type === 'file') {
        if (path.extname(pathname) !== '.js') {
            console.log('copy %s %s', pathname, newPath);
            fs.writeFileSync(newPath, fs.readFileSync(pathname));
            return;
        }

        console.log('traceur %s %s', pathname, newPath);
        var src = fs.readFileSync(pathname, {encoding:'utf8'});
        var options = {};
        var compiled = traceur.compile(src, options);
        
        fs.writeFileSync(newPath, compiled, {encoding:'utf8'});
    } 
    if (type === 'directory') {
        console.log('mkdir %s', newPath);
        fs.mkdirSync(newPath);
    }
});

运行时编译和单元测试

在项目开发过程,我们可不想写完一个文件就编译一次,所以我们还有个法子,在开发的时候使用运行时编译。等全部开发完,测试完,然后一次编译,上线。

在项目建立一个test-traceur.js文件

// 这段代码请原样复制
require('traceur').require.makeDefault(function(filename) {
  	return filename.indexOf('node_modules') === -1;
});

// 这里引入需要测试的目标文件
require('./test/my.js');

然后,运行测试: $ node test-traceur.js

程序就会自动编译my.js和my.js所依赖的文件,并且运行。

test-traceur.js文件里边的写法是必须这样的,只能引入一个测试文件,这是由trace-compiler设定的,具体可以参看其文档。

我有一个批量测试脚本,如果你需要的话:

  • 建立两个文件test-traceur.js, test-all.js

  • test-traceur.js:

require('traceur').require.makeDefault(function(filename) {
  	return filename.indexOf('node_modules') === -1;
});

require(process.argv[3]);
  • test-all.js:
var fs = require('fs');
var path = require('path');
var child_process = require('child_process');
var ROOT = path.join(__dirname, '../test');
var ROOT_TRACE = path.join(__dirname, 'test-traceur.js');


(function test(paths, i) { 
    if (i >= 0 && i < paths.length) {
        var stats = fs.statSync(paths[i]);
        if (stats.isFile()) {
            if (path.extname(paths[i]) === '.js') { 
                console.log('\ntest: %s', paths[i]);
                child_process.exec('node ' + ROOT_TRACE + ' -f ' + paths[i], function (err, stdout, stderr) {
                    if (err) {
                        throw err;
                    }
                    console.log('OK: %s', paths[i]);
                    test(paths, i + 1);
                });
            } else {
                test(paths, i + 1);
            }
        } else if (stats.isDirectory()) {
            var newPaths = fs.readdirSync(paths[i]).map(function (pathname) {
                return path.join(paths[i], pathname);
            }); 
            test(paths.slice(0, i).concat(newPaths, paths.slice(i + 1)), i);
        } else {
            test(paths.slice(0, i).concat(paths.slice(i + 1)), i);
        }
    } else {
        console.log('\ncomplete\n');
    }
} ([ROOT], 0));

test-all.js文件中,修改ROOT为要测试目录,运行 $ node test-all.js

在测试目录的文件就会依次运行。(他们和他们依赖的文件完全可以是ECMAScrip 6语法的文件)

最后,推荐你使用ROCORE简化你的异步开发

即便你不想改变你的express或者其他,你仍然能从ROCORE获得帮助,比如里边的scc和mcc这两个随时可用的异步工具:

串行:

var R = require('rocore');
var fs = require('fs');

R.scc(function* (ynext) {
    var [err, data] = yield fs.readFile(__dirname + 'my.conf', {encoding:'utf8'}, ynext);
    if (err) throw err;
    yield fs.writeFile(__dirname + 'new.conf', data, {encoding:'utf8'}, ynext);
    console.log('done');
});

并行:

var R = require('rocore');
var pool = require('mysql').createPool(/*配置*/);

R.scc(function* (ynext) {
    var {employee, order, position} = yield R.mcc(function* (ynext) {
        yield pool.query('SELECT * FROM employee', ynext('employee'));
        yield pool.query('SELECT * FROM order', ynext('order'));
        yield pool.query('SELECT * FROM position', ynext('position'));
    }, ynext);
    console.log(employee);
    console.log(order);
    console.log(position);
});

© 著作权归作者所有

tulayang
粉丝 2
博文 7
码字总数 6034
作品 3
崇明
私信 提问
张成文——ECMAScript 6 开发体系实践

2016年04月23日14:00時,在武汉市东湖高新技术开发区民院路38号纽宾凯鲁广国际酒店(光谷步行街地铁C出口省测绘局斜对面),舉行的规模在800人左右的2016源创会武汉站。由张成文(腾讯SNG web)分...

yunwangjun
2016/04/24
2.4K
1
一文读懂 JavaScript 和 ECMAScript 的区别

我曾试着在谷歌上检索 “ JavaScript 和 ECMAScript 之间的区别。” 最后我在得到的海量的混淆不清又相互矛盾的结果中彻底绝望了: “ECMAScript 是标准。” “JavaScript 是标准。” “ECM...

oschina
2017/11/06
2.6K
9
Mozilla CTO:JavaScript 未來將年年小改版

用来规范JavaScript(ECMAScript)的标准ECMA-262,其实作以及制定的工作由TC39(技术委员会,Technical Committee)负责,成员来自各大科技公司,像是Google、Mozilla、微软以及Apple等等,...

oschina
2015/10/10
3.4K
13
一文读懂JavaScript和ECMAScript的区别

一文读懂JavaScript和ECMAScript的区别 这篇文章代表了我目前对 JavaScript 和 ECMAScript 之间差异的理解。文章适合那些熟悉 JavaScript 但又想更加清楚地了解其与 ECMAScript、web 浏览器、...

城市之雾
2018/12/05
28
0
JavaScript 编年小史

1995 由 Netscape 公司雇员Brendan Eich 花不到 10 天时间开发出来。之所以叫 JavaScript,因为 Netscape 想开发一款类 Java 的脚本语言来增强 Web 技术用于和微软竞争。 1996 Netscape 提交...

CPPAlien
2018/05/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Vue warn]: Computed property "activeNames" was assigned to but it has no setter.

在使用 vue,element-ui时,如下代码 <template> <el-form :model="numberValidateForm" ref="numberValidateForm"> <el-form-item> <el-tabs v-model="activeNames" @tab-cl......

牧云橙
15分钟前
2
0
重构-改善既有代码的设计-6.2内联函数

6.2内联函数 动机 本书经常以简短的函数表现动作意图,这样会使代码更清晰易读。但有时候你会遇到某些函数,其内部代码和函数名称同样清晰易读。也可能你充够了该函数的内部实现,使其内容和...

还仙
16分钟前
2
0
Less 混入

混合类似于编程语言中的函数。 Mixins 是一组CSS属性,允许我们将一个类的属性嵌套于另一个类,被嵌入的类可以看作是变量,并且包含类名作为其属性,也就是说我们可以用一个类定义样式然后把...

凌兮洛
18分钟前
3
0
频繁FGC的真凶原来是它

频繁FGC的真凶原来是它 上周排查了一个线上问题,主要现象是CPU占用过高,jvm old区占用过高,同时频繁fgc,我简单排查了下就草草收场了,但是过后我对这个问题又进行了复查,发现问题没有那...

每天晒白牙
19分钟前
3
0
简单的树形菜单如何写

业务需求 数据结构中含有图片、名称、children的树形结构,需要展示出每一级的图片名称和图片,找了些树形图的插件,都没有展示大的图片的,一般都是小图标,就自己试着写一个包含图的简单的...

tianyawhl
21分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部