擔(dān)心ECMAScript 6來的太晚? 不需要! nodejs 0.10開啟ECMAScript 6任督二脈

首先辉浦,我們需要一個(gè)ECMAScript 6 -> ECMAScript5的編譯器,目前非常之多。這里推薦Google出品的traceur-compiler庄涡。

這里有一個(gè)編譯器列表: es6-tools弄屡。

原理

使用這些編譯器题禀,會(huì)幫助你把現(xiàn)在用ECMAScript 6語法編寫的javascript文件,編譯生成ECMAScript 5語法的靜態(tài)文件膀捷。

如果你是coffeescript的使用者迈嘹,那就很熟悉這種方式,類似coffeescript語法編譯成javascript文件全庸。

因?yàn)槭庆o態(tài)文件秀仲,所以不會(huì)存在運(yùn)行時(shí)再次編譯的性能問題。

另外壶笼,也提供了運(yùn)行時(shí)編譯神僵,幫助你直接測試ECMAScript 6語法編寫的文件。

traceur-compiler 使用入門

首先我想說覆劈,需求決定了技術(shù)的需要保礼。因?yàn)橐粋€(gè)項(xiàng)目的復(fù)雜度,我急于需要yield 和生成器來簡化異步判斷责语。因?yàn)閷?duì)express和koa那種java式的純面向?qū)ο笊钌畹姆锤兄茫?對(duì)JAVA C++ 和純面向?qū)ο蟮呐信谡希呀?jīng)是卡內(nèi)基·梅隆大學(xué)"反模塊化的又是反并行的"的家常便飯),我在長久的積累中坤候,短時(shí)間編寫出了ROCORE铝阐,并迅速測試優(yōu)化,迭代進(jìn)了0.2.17版本(事實(shí)上我現(xiàn)在使用的版本又有了新的改變铐拐,一個(gè)完全采用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文件,你會(huì)看到如下的代碼:
 
"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. 運(yùn)行生成的ECMAScript 5文件

    除了全局安裝纵穿,你還需要另外復(fù)制一份下隧,放到你的項(xiàng)目node_modules中,作為項(xiàng)目依賴谓媒。模塊名是traceur淆院。

    要運(yùn)行這個(gè)ec5.js文件,還需要引入traceur模塊句惯。在文件上部土辩,加上

    require('traceur');
    

    然后保存。運(yùn)行
    $ node ec5.js

    OK抢野,輸出101. 現(xiàn)在在nodejs 0.10中拷淘,能夠良好的運(yùn)行這個(gè)文件。

  2. 總結(jié)一下過程

    編寫ECMAScript 6文件 -> 編譯指孤,生成ECMAScript 5文件 -> 修改ECMAScript 5文件启涯,在最上邊加入require('traceur')保存 -> 運(yùn)行ECMAScript 5文件。

    在實(shí)際使用時(shí)恃轩,只需要在app.js(或者server.js)主文件中加入require('traceur')既可以结洼。

批量編譯

我們的項(xiàng)目文件可是有大量的文件,總不能一個(gè)一個(gè)動(dòng)手編譯吧详恼?!OK引几。這里有一個(gè)批量編譯的腳本程序昧互,復(fù)制然后保存到一個(gè)js文件里,設(shè)置要編譯的主目錄和要輸出的目標(biāo)目錄伟桅,ta會(huì)把主目錄的所有js文件編譯到目標(biāo)目錄敞掘,并且支持遞歸內(nèi)部文件,非js文件被原樣不變的復(fù)制到目標(biāo)目錄楣铁。

另外玖雁,建議只編譯復(fù)制lib目錄中的文件,其他目錄的文件手動(dòng)復(fù)制到目標(biāo)目錄盖腕。

// 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);
    }
});

運(yùn)行時(shí)編譯和單元測試

在項(xiàng)目開發(fā)過程赫冬,我們可不想寫完一個(gè)文件就編譯一次浓镜,所以我們還有個(gè)法子,在開發(fā)的時(shí)候使用運(yùn)行時(shí)編譯劲厌。等全部開發(fā)完膛薛,測試完,然后一次編譯补鼻,上線哄啄。

在項(xiàng)目建立一個(gè)test-traceur.js文件

// 這段代碼請(qǐng)?jiān)瓨訌?fù)制
require('traceur').require.makeDefault(function(filename) {
    return filename.indexOf('node_modules') === -1;
});

// 這里引入需要測試的目標(biāo)文件
require('./test/my.js');

然后,運(yùn)行測試:
$ node test-traceur.js

程序就會(huì)自動(dòng)編譯my.js和my.js所依賴的文件风范,并且運(yùn)行咨跌。

test-traceur.js文件里邊的寫法是必須這樣的,只能引入一個(gè)測試文件硼婿,這是由trace-compiler設(shè)定的锌半,具體可以參看其文檔。

我有一個(gè)批量測試腳本加酵,如果你需要的話:

  • 建立兩個(gè)文件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為要測試目錄,運(yùn)行
$ node test-all.js

在測試目錄的文件就會(huì)依次運(yùn)行猪腕。(他們和他們依賴的文件完全可以是ECMAScrip 6語法的文件)

最后冗澈,推薦你使用ROCORE簡化你的異步開發(fā)

即便你不想改變你的express或者其他,你仍然能從ROCORE獲得幫助陋葡,比如里邊的scc和mcc這兩個(gè)隨時(shí)可用的異步工具:

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);
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末亚亲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子腐缤,更是在濱河造成了極大的恐慌捌归,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岭粤,死亡現(xiàn)場離奇詭異惜索,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)剃浇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門巾兆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人虎囚,你說我怎么就攤上這事角塑。” “怎么了淘讥?”我有些...
    開封第一講書人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵圃伶,是天一觀的道長。 經(jīng)常有香客問我,道長窒朋,這世上最難降的妖魔是什么搀罢? 我笑而不...
    開封第一講書人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮炼邀,結(jié)果婚禮上魄揉,老公的妹妹穿的比我還像新娘。我一直安慰自己拭宁,他們只是感情好洛退,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杰标,像睡著了一般兵怯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腔剂,一...
    開封第一講書人閱讀 52,874評(píng)論 1 314
  • 那天媒区,我揣著相機(jī)與錄音,去河邊找鬼掸犬。 笑死袜漩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湾碎。 我是一名探鬼主播宙攻,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼介褥!你這毒婦竟也來了座掘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤柔滔,失蹤者是張志新(化名)和其女友劉穎溢陪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睛廊,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡形真,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了超全。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咆霜。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖卵迂,靈堂內(nèi)的尸體忽然破棺而出裕便,到底是詐尸還是另有隱情绒净,我是刑警寧澤见咒,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站挂疆,受9級(jí)特大地震影響改览,放射性物質(zhì)發(fā)生泄漏下翎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一宝当、第九天 我趴在偏房一處隱蔽的房頂上張望视事。 院中可真熱鬧,春花似錦庆揩、人聲如沸俐东。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虏辫。三九已至,卻和暖如春锈拨,著一層夾襖步出監(jiān)牢的瞬間砌庄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來泰國打工奕枢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留娄昆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓缝彬,卻偏偏與公主長得像萌焰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子跌造,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容