亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

為何 ES Module 如此姍姍來遲

xuexiangjys / 1965人閱讀

摘要:最大的好處是對(duì)用戶而言透明,可惜原因如前所述,此方案已否定。鑒于已經(jīng)在正式提案中,倘若討論持續(xù)僵持不下,不出意外將會(huì)隨著時(shí)間推移而正式成為規(guī)范。月碰頭會(huì)的與會(huì)者紛紛表示這次會(huì)議進(jìn)展令人愉快,會(huì)議內(nèi)容匯總在此,以及一些補(bǔ)充。

說明:本文發(fā)布之后,此問題的推進(jìn)峰回路轉(zhuǎn),不停有新內(nèi)容。文末新增一節(jié) Updates,跟進(jìn)本文發(fā)布之后的 ES Module 標(biāo)準(zhǔn)化進(jìn)展情況。

瀏覽器大戰(zhàn)多年了熱度依舊高漲,大家終于在 JS 新特性的部署上達(dá)成一致紛紛追趕最新標(biāo)準(zhǔn),然而 ES2015 中的 ES Module 這個(gè)萬眾期待的重要特性卻始終遲遲未能實(shí)現(xiàn)。

等 2020 年回望歷史,倘若我們錯(cuò)過了 ES Module 這艘船而 Node.js 死在汪洋大海之中,沒有任何其他技術(shù)問題的重要性可以與此相比。
-- issac

Module 的規(guī)范是完工了的,只是對(duì)于模塊如何加載和解析留給了“實(shí)現(xiàn)環(huán)境決定”——按歷史經(jīng)驗(yàn),問題往往就出現(xiàn)在這一環(huán)。當(dāng)然了不是燙手山芋 W3C 也不會(huì)就這么輕松甩開對(duì)吧,事實(shí)上這也不是 W3C 一家的事情,牽涉到 TC39、Node 技術(shù)委員會(huì)、Node 和前端兩個(gè)開發(fā)社群,以及 npm 公司。

故事很長,我們從頭說起。importexport 的語法規(guī)范很明確,模塊的解析器 V8 早已實(shí)現(xiàn),萬事俱備只欠加載。區(qū)區(qū)加載能有多麻煩?

Module 的特性

在新規(guī)范下,JavaScript 程序劃分成兩種類型:腳本(我們以前寫的傳統(tǒng)JS)和模塊(ES規(guī)范中新定義的 Module),模塊有四項(xiàng)于腳本不同的特性:

強(qiáng)制嚴(yán)格模式(無法取消)

執(zhí)行環(huán)境在一個(gè)非全局的作用域中

可以使用 import 導(dǎo)入其他 Module 的 binding

可以使用 export 導(dǎo)出本 Module 的 binding

看上去規(guī)則簡單明白,但是要讓一個(gè)解析器(parser)區(qū)分兼容這兩種模式還挺復(fù)雜的。

解析器的難題
看看代碼中是否包含 importexport 關(guān)鍵字不就可以判斷它的類型了么?

不行。首先猜測(cè)用戶意圖是個(gè)危險(xiǎn)行為,如果你猜對(duì)了,就更加掩蓋了猜錯(cuò)可能會(huì)造成的風(fēng)險(xiǎn)。

而嚴(yán)格模式,除了運(yùn)行時(shí)的一些要求之外還定義了幾個(gè)語法錯(cuò)誤:

使用 with 關(guān)鍵字;

使用八進(jìn)制字面量(如 010);

函數(shù)參數(shù)重名;

對(duì)象屬性重名(僅在 ES5 環(huán)境。ES6 取消了此錯(cuò)誤);

使用 implements、interfacelet、packageprivate、protected、publicstaticyield 作為標(biāo)識(shí)符。

這些語法錯(cuò)誤需要在解析時(shí)就拋出來。所以如果以腳本模式解析到了文件末尾才發(fā)現(xiàn)有 export,就得從頭重新解析整個(gè)文件來捕捉上述語法錯(cuò)誤。

那我們換一條路,開始先假定為模塊進(jìn)行解析代碼。既然 Module 語法相當(dāng)于嚴(yán)格模式 + 導(dǎo)入導(dǎo)出 (importexport),我們可以用腳本模式 + 導(dǎo)入導(dǎo)出的語法來解析整個(gè)文件。然而這種解析規(guī)則已經(jīng)超越了規(guī)范定義,這么扭曲的路線可以預(yù)見它成為 Bug 源泉的樣子。

危險(xiǎn)但不是不可能。OK 真正的麻煩來了:按照規(guī)范 importexport 都是可選的——你可以寫一個(gè) Module,既不導(dǎo)入也不導(dǎo)出任何東西,它只是對(duì)全局作用域做些小動(dòng)作,比如這樣:

// 一個(gè)合法的 Module
window.addEventListener("load", function() {
    console.log("Window is loaded");
});
// WAT!

總的來說,包含 importexport 表明它一定是個(gè) Module,但沒有這兩個(gè)關(guān)鍵字卻不能證明它不是 Module。 ╮(╯_╰)╭

區(qū)分 JavaScript 文件類型的任務(wù)沒法放在解析器里自動(dòng)完成,我們需要在解析文件之前就知道它的類型。

瀏覽器的辦法

這就是為什么瀏覽器的模塊引用是這個(gè)寫法:

當(dāng)瀏覽器開始加載這個(gè) foo.js,它會(huì)邊加載邊解析,碰到 import { bar } from "./bar.js" 的第一時(shí)間開始加載依賴的 bar.js,加載完之后對(duì)其解析,檢查其中是否導(dǎo)出了 bar。如此往復(fù)完成整個(gè) Module 的解析。

Node.js 呢

到了 Node.js,新的問題來了。

作為世界上最大的軟件包倉庫,npm 中現(xiàn)有的軟件包都是 CommonJS 規(guī)范。ES Module 需要能夠與 CommonJS 模塊共存,允許開發(fā)者們逐步轉(zhuǎn)向新的語法。

所謂的共存,主要是指 import { foobar } from "foobar" 語法要支持 CJS Module 和 ES Module 兩種包格式——如果 import 只能用來導(dǎo)入 ES Module 而 require 可以導(dǎo)入任意模塊,那么所有人都會(huì)用 require;如果 importrequire 各自負(fù)責(zé)導(dǎo)入各自的格式,那么開發(fā)者就需要知道所有依賴的庫的格式,使用相應(yīng)語法來導(dǎo)入它,并且在依賴的庫們更換到新格式的時(shí)候修改自己的代碼去兼容……在可預(yù)見的 CommonJS -> ES Module 漫長過渡期里這樣的負(fù)擔(dān)對(duì)社區(qū)而言不可接受。

為此社區(qū)提出了不少方案,(好消息)經(jīng)過大量的討論之后現(xiàn)在已經(jīng)集中到兩個(gè)選擇還在討論:

解析器自動(dòng)檢測(cè)。最大的好處是對(duì)用戶而言透明,可惜原因如前所述,此方案已否定。

使用 "use module" 標(biāo)注。一想到 JS 的未來永遠(yuǎn)都要在文件開頭貼這么個(gè)膏藥大家就不能忍了。否定。

新的文件后綴 .jsm。主要問題是現(xiàn)有社區(qū)工具鏈全部需要更新才能支持,另外和瀏覽器實(shí)現(xiàn)的統(tǒng)一也要考慮。

package.json 上發(fā)揮。這個(gè)門類下的提議就更多了,比如添加一個(gè) module 字段逐步替代掉 main

{
    // ...
    "module": "lib/index.js",
    "main": "old/index.js",
    // ...
}

這個(gè)方案只適用單入口的情況,對(duì)多文件(比如 require("foo/bar.js")的場(chǎng)景)就不行了。那就改成 modules 字段(復(fù)雜度陡升):

{
    // ...
    // files:
    "modules": ["lib/hello.js", "bin/hello.js"],

    // directories:
    "modules": ["lib", "bin"],

    // files and directories:
    "modules": ["lib", "bin", "special.js"],

    // if package never uses CJS Modules
    "modules": ["."],
}

這還沒完,更多方案就不詳述了,大家可以到 Node.js Wiki 上查看。

就個(gè)人偏好而言,盡管所有的方案都有利有弊,而 package.json 這條路為了兼容各種需求,修改版的提案已經(jīng)越來越復(fù)雜,比較起來 .jsm 后綴倒是愈發(fā)顯得簡單清晰了。我更喜歡這個(gè)干凈的解決方案。

現(xiàn)在的進(jìn)展(2016.04.15)

閱讀需要支付1元查看
<