在瀏覽器中使用javascript module(譯)

在瀏覽器中使用JS module

簡(jiǎn)介

現(xiàn)在苞氮,所有主流瀏覽器都已經(jīng)支持JS module(Chrome舷夺、Edge猖辫、Safari荔仁、Firefox)~這篇文章將為你講解如何在瀏覽器中使用JS module伍宦,如何負(fù)責(zé)的部署它們,以及chrome團(tuán)隊(duì)如何努力的使JS module變的更好乏梁。

什么是JS module

JS module(或者稱(chēng)作ES module雹拄,ECMAScript module)是一個(gè)主要的新特性,或者說(shuō)是一系列新特性掌呜。你可能已經(jīng)使用過(guò)第三方的模塊加載系統(tǒng)滓玖。CommonJsnodeJsAMDrequireJs 等等质蕉。這些模塊加載系統(tǒng)都有一個(gè)共同點(diǎn):它們?cè)试S你執(zhí)行導(dǎo)入導(dǎo)出操作势篡。

javascript現(xiàn)在已經(jīng)為模塊化制定了標(biāo)準(zhǔn)語(yǔ)法。有了JS module模暗,你可以用export關(guān)鍵字去導(dǎo)出任何東西禁悠。你可以導(dǎo)出constfunction兑宇,或者任何其他變量綁定或聲明碍侦。你需要做的只是在變量聲明前加個(gè)export或者用export去聲明它。

// lib.mjs
export const repeat = (string) => `${string} ${string}`;
export function shout(string) {
  return `${string.toUpperCase()}!`;
}

你可以使用import從任何其他模塊導(dǎo)入模塊隶糕。這里瓷产,我們從lib模塊中引入repeatshout方法,并在main模塊(當(dāng)前模塊)中使用它們枚驻。

// ?? main.mjs
import {repeat, shout} from './lib.mjs';
repeat('hello');
// → 'hello hello'
shout('Modules in action');
// → 'MODULES IN ACTION!'

你也可以使用export default從模塊中導(dǎo)出一個(gè)默認(rèn)值濒旦。

// ?? lib.mjs
export default function(string) {
  return `${string.toUpperCase()}!`;
}

export default導(dǎo)出的模塊可以在其它模塊中使用任意名稱(chēng)去import

// ?? main.mjs
import repeat from './lib.mjs';
//     ^^^^^
// ?? main2.mjs
import shout from './lib.mjs';
//     ^^^^^

JS module普通的js腳本有些不同:

  • module默認(rèn)使用的是嚴(yán)格模式(strick module
  • 不支持html風(fēng)格的注釋
    // Error: 不要在javascript中使用html風(fēng)格的注釋
    const x = 42; <!-- TODO: Rename x to y.
    // Error: 使用普通的單行注釋
    const x = 42; // TODO: Rename x to y.
    
  • 模塊具有自己的作用域再登。這意味著在模塊中使用var foo = 42并不會(huì)創(chuàng)建一個(gè)全局變量foo尔邓,不能通過(guò)window.foo去訪問(wèn)。這點(diǎn)和普通的js腳本不同锉矢。
  • exportimport關(guān)鍵字僅可在模塊系統(tǒng)中使用----所以不能在普通的js腳本中使用梯嗽。

由于有這些不同點(diǎn),當(dāng)相同的js腳本分別被當(dāng)做JS module普通js腳本執(zhí)行時(shí)沽损,可能有不同的行為表現(xiàn)灯节。所以,javascript運(yùn)行環(huán)境必須知道引入的腳本是不是一個(gè)JS module

在瀏覽器中使用JS modules

在web應(yīng)用中显晶,你可以將<script>標(biāo)簽的type屬性設(shè)置為module贷岸,這樣瀏覽器就會(huì)把引入的腳本識(shí)別為JS module

<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>

瀏覽器會(huì)識(shí)別typ="module"屬性磷雇,并忽略設(shè)置有nomodule屬性的腳本偿警。這意味著你可以向支持模塊加載的瀏覽器提供基于JS module的代碼,同時(shí)讓不支持模塊加載的瀏覽器回退到普通js腳本模式唯笙。
如果在表現(xiàn)上螟蒸,這種區(qū)分腳本的能力驚人的有用。
想一想:只有現(xiàn)代瀏覽器支持modules崩掘,如果瀏覽器能夠識(shí)別你的模塊代碼七嫌,那么它肯定也支持在模塊化標(biāo)準(zhǔn)之前的新的js特性,比如:箭頭函數(shù)苞慢,async-await诵原。
你不需要再去編譯那些使用新特性寫(xiě)的代碼!能為現(xiàn)代瀏覽器提供更小挽放、很大程度上不需要再編譯的代碼绍赛。只有不支持模塊加載的瀏覽器會(huì)請(qǐng)求設(shè)置nomodule的腳本。

特定于瀏覽器環(huán)境下辑畦, JS module普通js腳本的區(qū)別

前面已經(jīng)說(shuō)過(guò)吗蚌,JS module普通js加載是不同的。
在上邊我們列舉了一些平臺(tái)無(wú)關(guān)的差異纯出,在瀏覽器環(huán)境中它們還有一些不同點(diǎn)蚯妇。
比如,JS module只會(huì)被瀏覽器解析并執(zhí)行一次暂筝,普通js腳本每一次通過(guò)<script>引入箩言,瀏覽器都會(huì)去解析和執(zhí)行它。

<script src="classic.js"></script>
<script src="classic.js"></script>
<!-- classic.js 會(huì)被多次解析 -->

<script type="module" src="module.mjs"></script>
<script type="module" src="module.mjs"></script>
<script type="module">import './module.mjs';</script>
<!-- module.mjs 只會(huì)被解析一次 -->

而且乖杠,JS module腳本和依賴(lài)有了跨域限制分扎,這意味著任何跨域的JS module腳本都必須有正確的http頭部信息澄成。如:Access-Control-Allow-Origin: *胧洒。而普通的js腳本并沒(méi)有這些限制。
另一個(gè)不同與async屬性有關(guān)墨状,async屬性可以使js腳本的下載不會(huì)阻塞HTML解析(就像defer)卫漫,但同時(shí)async屬性也會(huì)使得腳本在加載完成后立即執(zhí)行(defer是等到html解析完成后執(zhí)行),不能保證腳本的執(zhí)行順序肾砂,也不會(huì)等待html解析完成列赎。
async屬性在內(nèi)聯(lián)普通js腳本不生效,不過(guò)在內(nèi)聯(lián)JS module模式下可以生效镐确。

關(guān)于文件擴(kuò)展名

你可能已經(jīng)注意到我們?cè)趯?xiě)模塊代碼時(shí)是用.mjs作為文件擴(kuò)展名的包吝。當(dāng)然饼煞,在web中,只要http的響應(yīng)頭中提供了JavaScript MIME typetext/javascript字段诗越,文件擴(kuò)展名并不是特別重要砖瞧。
而且,瀏覽器通過(guò)<script>標(biāo)簽上的type屬性就可以知道這是不是一個(gè)JS module模塊嚷狞。

但是块促,我們?nèi)匀煌扑]使用.mjs作為文件擴(kuò)展名,原因有以下兩個(gè)方面:

  1. 在開(kāi)發(fā)中床未,我們可以很容易的通過(guò)擴(kuò)展名去辨識(shí)文件是一個(gè)模塊而不是一個(gè)普通的腳本文件(僅僅靠查看代碼去辨別不會(huì)總行得通)竭翠。正如前邊提到的,瀏覽器對(duì)待模塊代碼和普通腳本文件是完全不同的薇搁。
  2. 符合node.js規(guī)范斋扰。nodeJs實(shí)驗(yàn)?zāi)K僅僅支持.mjs擴(kuò)展名的文件。

模塊說(shuō)明符(Module specifiers)

當(dāng)我們使用import時(shí)啃洋,最后邊用來(lái)說(shuō)明模塊位置的字符串叫做 module specifiersimport specifier褥实,在我們前面的例子中, module specifier'./lib.mjs'

import {shout} from './lib.mjs';
//                  ^^^^^^^^^^^

在瀏覽器中裂允,模塊說(shuō)明符還有一些限制损离。
目前是不支持 裸模塊 (指像在node中只通過(guò)包名引入)的。這個(gè)規(guī)定讓瀏覽器可以允許自定義模塊加載器對(duì)像下面這樣的空模塊說(shuō)明符賦予特殊的意義绝编。

// Not supported (yet):
import {shout} from 'jquery';
import {shout} from 'lib.mjs';
import {shout} from 'modules/lib.mjs';

下面這些引用方式是合法的

// Supported:
import {shout} from './lib.mjs';
import {shout} from '../lib.mjs';
import {shout} from '/modules/lib.mjs';
import {shout} from 'https://simple.example/modules/lib.mjs';

到現(xiàn)在為止僻澎,模塊說(shuō)明符必須是完整的URL,或以/ ./ ../開(kāi)頭的相對(duì)URL十饥。

模塊默認(rèn)是延遲執(zhí)行的(defer)

普通js腳本默認(rèn)會(huì)阻塞html解析窟勃。你可以加一個(gè)defer屬性,讓腳本的下載和html解析并發(fā)執(zhí)行逗堵。

defer and async

JS module腳本默認(rèn)就有defer屬性秉氧,所以,沒(méi)有必要再加一個(gè)defer屬性到<script type="module">標(biāo)簽上!
不僅僅是主模塊蜒秤,所有模塊的加載都和html解析是并行的汁咏。

其他模塊特性

Dynamic import()

到現(xiàn)在,我們只用了靜態(tài)的import作媚。使用靜態(tài)模塊攘滩,在主程序運(yùn)行之前,所有的模塊代碼都必須加載并執(zhí)行完畢纸泡。
有時(shí)漂问,你并不想在一開(kāi)始就加載某個(gè)模塊,而是想在需要的時(shí)候隨時(shí)動(dòng)態(tài)去請(qǐng)求(如:當(dāng)用戶點(diǎn)擊一個(gè)鏈接或標(biāo)簽),這樣做能減少應(yīng)用的初始加載時(shí)間蚤假,提升頁(yè)面性能栏饮。
Dynamic import()就可以用來(lái)解決這種問(wèn)題~

<script type="module">
  (async () => {
    const moduleSpecifier = './lib.mjs';
    const {repeat, shout} = await import(moduleSpecifier);
    repeat('hello');
    // → 'hello hello'
    shout('Dynamic import in action');
    // → 'DYNAMIC IMPORT IN ACTION!'
  })();
</script>

和靜態(tài)import不一樣,動(dòng)態(tài)import()也可以在普通的腳本文件中使用磷仰。這提供了一種在現(xiàn)有代碼中逐步使用模塊加載的方式抡爹。更多信息,點(diǎn)擊Dynamic import()查看

import.meta

另一個(gè)模塊相關(guān)的新特性是import.meta芒划,從這個(gè)屬性我們可以獲得當(dāng)前模塊的元數(shù)據(jù)冬竟。你所能得到的確切元數(shù)據(jù)并沒(méi)有作為ECMAScript規(guī)范的一部分。它取決于你的宿主環(huán)境民逼,在瀏覽器和NodeJs中你可能得到不同的元數(shù)據(jù)泵殴,比如:
下面是一個(gè)瀏覽器中使用import.meta的例子。默認(rèn)情況下拼苍,圖片相對(duì)于HTML文檔的當(dāng)前url加載的笑诅。import.meta.url使得我們可以相對(duì)于當(dāng)前模塊的路徑去加載圖片。

function loadThumbnail(relativePath) {
  const url = new URL(relativePath, import.meta.url);
  const image = new Image();
  image.src = url;
  return image;
}

const thumbnail = loadThumbnail('../img/thumbnail.png');
container.append(thumbnail);

性能建議

保持使用打包工具

JS modules使得不使用打包工具(webpack, Rollup, 或Parcel)開(kāi)發(fā)網(wǎng)站成為可能疮鲫。在下列場(chǎng)景中吆你,你就可以直接使用JS module去開(kāi)發(fā)應(yīng)用。

  • 本地開(kāi)發(fā)環(huán)境中
  • 在總模塊少于100和依賴(lài)樹(shù)相對(duì)較淺(即俊犯,最大深度小于5)的小型Web App中

然而妇多,我們?cè)趯?duì)chrome加載管道進(jìn)行瓶頸分析時(shí),加載了由大約300模塊組成的模塊化庫(kù)燕侠,此時(shí)打包應(yīng)用程序的加載性能優(yōu)于未打包應(yīng)用程序者祖。

渲染器主線程時(shí)間分解圖

其中一個(gè)原因是因?yàn)殪o態(tài)的import / export是可以靜態(tài)分析的,因此绢彤,打包工具可以通過(guò)消除未使用的export來(lái)優(yōu)化代碼七问。靜態(tài)的importexport不僅僅是語(yǔ)法,更是一種新的工具特性!


同樣的chrome開(kāi)發(fā)者工具的代碼覆蓋率特性可以幫助你識(shí)別你是否將不必要的代碼推送給了用戶茫舶。我們還建議開(kāi)發(fā)者使用代碼分割工具分割代碼械巡,將首屏渲染不需要的腳本延遲加載。

打包和不打包的權(quán)衡
在web開(kāi)發(fā)中饶氏,每一件事都需要去做權(quán)衡讥耗。未打包的代碼可能會(huì)用戶降低首次訪問(wèn)頁(yè)面的性能(冷緩存),但與一個(gè)沒(méi)有做代碼分割的包相比嚷往,它可以提高后續(xù)訪問(wèn)的加載性能葛账。

對(duì)一個(gè)200kb的代碼庫(kù),將其中一個(gè)細(xì)粒度的模塊分割出來(lái)皮仁,將其作為用戶后續(xù)訪問(wèn)從服務(wù)器獲取的唯一內(nèi)容比每次都要下載整個(gè)代碼庫(kù)好得多。

使用更細(xì)粒度的模塊

養(yǎng)成寫(xiě)更小、細(xì)粒度模塊代碼的習(xí)慣贷祈。在開(kāi)發(fā)中趋急, 每個(gè)(文件)模塊只含有少數(shù)幾個(gè)導(dǎo)出 要比 將多個(gè)導(dǎo)出寫(xiě)到一個(gè)文件 好的多。

考慮這樣一種情況势誊,util.mjs文件導(dǎo)出三個(gè)方法分別是:drop呜达,pluckzip

export function drop() { /* … */ }
export function pluck() { /* … */ }
export function zip() { /* … */ }

如果你的代碼只需要pluck 方法,你可能要這樣寫(xiě):

import { pluck } from './util.mjs';

在這種情況下(沒(méi)有進(jìn)行構(gòu)建時(shí)打包)粟耻,即使你只需要pluck一個(gè)導(dǎo)出查近,瀏覽器仍然需要去下載、解析和編譯整個(gè)utils.mjs文件挤忙。真是糟糕呢~

如果pluck沒(méi)有和drop霜威、zip有任何共享模塊的話,最好的做法是將它拆分為更細(xì)粒度的模塊文件./pluck.mjs册烈。

export function pluck() { /* … */ }

這樣戈泼,我們可以只導(dǎo)入pluck,而不用瀏覽器去處理dropzip模塊:

import { pluck } from './pluck.mjs';

提示:您可以在此處使用命名導(dǎo)出export default

這樣不僅能使你的代碼保持良好和簡(jiǎn)單赏僧,還能減少打包工具處理無(wú)用代碼的時(shí)間大猛。如果其中一個(gè)模塊沒(méi)有被使用,那它永遠(yuǎn)不會(huì)被import淀零,所以瀏覽器永遠(yuǎn)不會(huì)使用它挽绩。而那些被使用的模塊會(huì)被瀏覽器每個(gè)單獨(dú)緩存下來(lái)。

使用更細(xì)粒度的模塊拆分可以讓你的代碼為將來(lái)或許可以直接使用原生打包解決方案做好準(zhǔn)備驾中。

預(yù)加載模塊

你可以使用<link rel="modulepreload">進(jìn)一步優(yōu)化你的模塊的加載(delivery)琼牧。
這樣,瀏覽器可以預(yù)加載和預(yù)編譯模塊以及它的依賴(lài)哀卫。

<link rel="modulepreload" href="lib.mjs">
<link rel="modulepreload" href="main.mjs">
<script type="module" src="main.mjs"></script>
<script nomodule src="fallback.js"></script>

這種方式對(duì)有大型依賴(lài)樹(shù)的應(yīng)用至關(guān)重要巨坊。沒(méi)有rel="modulepreload",瀏覽器需要發(fā)起多次http請(qǐng)求去得到整個(gè)依賴(lài)樹(shù)此改。然后趾撵,如果你用rel="modulepreload"聲明了整個(gè)應(yīng)用的腳本列表,瀏覽器就不需要去逐步的去解析并請(qǐng)求這些依賴(lài)共啃。

使用HTTP/2

盡可能的使用HHTP/2總是很好的性能建議占调,即使僅僅是去使用它的多路復(fù)用特性。
使用HTTP/2多路復(fù)用移剪,可以同時(shí)處理多個(gè)請(qǐng)求和響應(yīng)信息究珊,這對(duì)模塊依賴(lài)樹(shù)的加載很有利。

Chrome團(tuán)隊(duì)研究過(guò)HTTP/2的另一個(gè)新特性纵苛,HTTP/2服務(wù)端推送剿涮,是否能成為部署高度模塊化應(yīng)用的解決方案言津。不幸的是,HTTP/2 服務(wù)端推送難做到取试,web服務(wù)器和瀏覽器的實(shí)現(xiàn)目前還沒(méi)有針對(duì)高度模塊化的web應(yīng)用實(shí)例進(jìn)行優(yōu)化悬槽。
比如,我們很難去做到只推送用戶沒(méi)有緩存的數(shù)據(jù)瞬浓,而且通過(guò)向服務(wù)端去發(fā)送整個(gè)客戶端的緩存狀態(tài)會(huì)造成一種隱私風(fēng)險(xiǎn)初婆。

無(wú)論如何,繼續(xù)使用HTTP/2猿棉!只需要記住HTTP/2服務(wù)端推送(很不幸)不是一個(gè)好辦法磅叛。

JS modules的使用現(xiàn)狀

JS modules正逐漸的被web開(kāi)發(fā)者接受,我們的用戶統(tǒng)計(jì)數(shù)據(jù)顯示當(dāng)前有0.08%的頁(yè)面在使用<script type="module">萨赁,這個(gè)數(shù)據(jù)排除了其他使用方式弊琴,如import()worklets

對(duì)于JS modules,接下來(lái)我們會(huì)做什么

Chrome團(tuán)隊(duì)正在努力從多方面去提升JS modules的開(kāi)發(fā)體驗(yàn)位迂,下面我們來(lái)講講其中的一部分访雪。

更快更確定的模塊解析算法

我們對(duì)模塊解析算法進(jìn)行了修改,解決了速度和確定性方面的不足掂林。新算法現(xiàn)在已經(jīng)同時(shí)存在于HTML規(guī)范和ECMAScript規(guī)范中臣缀,而且已經(jīng)在Chrome 63中實(shí)現(xiàn)。希望這個(gè)改進(jìn)能在其他瀏覽器中盡快實(shí)現(xiàn)泻帮。

新算法更加的高效和快速精置。舊算法在依賴(lài)關(guān)系計(jì)算上的復(fù)雜度是二次方的(n2),舊的Chrome也是如此锣杂,新的算法是線性的(n)脂倦。

而且,新算法以一種確定的方式去報(bào)告解析錯(cuò)誤元莫。給定一個(gè)包含多個(gè)錯(cuò)誤的依賴(lài)關(guān)系圖赖阻,對(duì)造成解析失敗的根本原因,舊算法多次運(yùn)行可能報(bào)告不同的錯(cuò)誤踱蠢。這對(duì)調(diào)試造成了不必要的麻煩火欧。而新算法保證每次都報(bào)告相同的錯(cuò)誤信息。

Worklets and web workers

Chrome現(xiàn)在在實(shí)現(xiàn)worklets茎截,這將允許web開(kāi)發(fā)者去自定義瀏覽器底層的硬編碼邏輯苇侵。使用worklets,web開(kāi)發(fā)者可以將一個(gè)JS模塊提供給渲染管道或者音頻管道(未來(lái)可能會(huì)有更多的管道支持)企锌。
Chrome 65 支持使用PaintWorklet去控制DOM元素的繪制榆浓。

const result = await css.paintWorklet.addModule('paint-worklet.mjs');

Chrome 66 支持 AudioWorklet,允許你控制用自己的代碼控制音頻進(jìn)程撕攒。同時(shí)這個(gè)版本還開(kāi)始了一個(gè) 實(shí)驗(yàn)性質(zhì)的AnimationWorklet陡鹃,讓開(kāi)發(fā)者能夠創(chuàng)建scroll-linked和其它高性能的程序動(dòng)畫(huà)(這塊不太理解)烘浦。

最后, LayoutWorklet(又叫做 the CSS Layout API)已經(jīng)應(yīng)用在Chrome 67上杉适。

我們正在努力為Chrome添加支持谎倔,使得開(kāi)發(fā)者可以在專(zhuān)用的web Workers中使用JS modules柳击。你現(xiàn)在就可以嘗試這個(gè)新特性:chrome://flags/#enable-experimental-web-platform-features enabled.(在chrome輸入欄輸入開(kāi)啟)猿推。

const worker = new Worker('worker.mjs', { type: 'module' });

JS module對(duì)shared wrokers和service workers的支持也會(huì)很快到來(lái):

const worker = new SharedWorker('worker.mjs', { type: 'module' });
const registration = await navigator.serviceWorker.register('worker.mjs', { type: 'module' });

包名映射(Package name maps)

在Node.js/npm中,我們常用模塊的包名去引入模塊捌肴。如:

import moment from 'moment';
import { pluck } from 'lodash-es';

目前蹬叭,按照HTML規(guī)范,這樣的 裸模塊 會(huì)拋出異常状知。我們的 包名映射建議允許這樣的代碼在瀏覽器中正常工作秽五,包括生產(chǎn)環(huán)境中。包名映射是一種json數(shù)據(jù)饥悴,能幫助瀏覽器將 裸模塊 形式的說(shuō)明符轉(zhuǎn)換成完整的url坦喘。

包名映射現(xiàn)在還在提案階段。盡管我們已經(jīng)思考了很多關(guān)于如何處理各種用例的問(wèn)題西设,但我們?nèi)匀辉谂c社區(qū)進(jìn)行溝通瓣铣,而且還沒(méi)有寫(xiě)出一個(gè)完整的規(guī)范。歡迎大家提任何反饋(最下方我會(huì)給出原文鏈接)贷揽。

Web打包:原生捆綁包

Chrome開(kāi)發(fā)團(tuán)隊(duì)正在探索一種原生的web打包格式作為一種新方式去發(fā)布web應(yīng)用棠笑。原生web打包的核心特性是:

Signed HTTP Exchanges允許瀏覽器信任一個(gè)簽名的HTTP請(qǐng)求/響應(yīng)是被當(dāng)前源要求生成的。
Bundled HTTP Exchanges,也就是禽绪,一個(gè)交換集蓖救,每個(gè)交換集可以是已簽名的或者未簽名的,其中有一些元數(shù)據(jù)描述如何將bundled解釋為一個(gè)整體印屁。

組合起來(lái)循捺,這樣的web打包格式將使多個(gè)同源資源安全地嵌入到單個(gè)HTTP GET響應(yīng)中。

現(xiàn)在的打包工具雄人,如webpack, Rollup, or Parcel 目前只會(huì)發(fā)出一個(gè)javascript包从橘,丟失了原始獨(dú)立模塊和資源的語(yǔ)義。使用原生捆綁包柠衍,瀏覽器可以將資源解包到他們的原始形式洋满。

簡(jiǎn)單來(lái)說(shuō),你可以將Bundled HTTP Exchange想象成一組資源珍坊,可以通過(guò)一個(gè)目錄(manifest)以任何順序訪問(wèn)它牺勾,而且,所包含的資源可以根據(jù)他們的相對(duì)重要性進(jìn)行有效的存儲(chǔ)和標(biāo)記阵漏,同時(shí)保持了單個(gè)文件的概念驻民。

由于這個(gè)特點(diǎn)翻具,原生捆綁包可以提升調(diào)試體驗(yàn)。在從devtools中查看資源時(shí)回还,瀏覽器可以在不需要復(fù)雜的代碼映射的情況下確定原始模塊裆泳。

原生捆綁包的透明性提供了各種優(yōu)化機(jī)會(huì)。比如柠硕,如果瀏覽器本地已經(jīng)有了一部分捆綁包的緩存工禾,那么它可以將該信息告訴web服務(wù)器,然后只需要下載缺失的部分蝗柔。

Chrome已經(jīng)支持了一部分提議(SignedExchanges)但是捆綁包以及對(duì)高度模塊化應(yīng)用的應(yīng)用仍處于探索階段闻葵。
Your feedback is highly welcome on the repository or via email to loading-dev@chromium.org

分層API(Layered APIs)

發(fā)布新特性和web API需要持續(xù)的維護(hù)和運(yùn)行時(shí)成本 ---- 每一個(gè)新特性都會(huì)污染瀏覽器命名空間癣丧,增加啟動(dòng)成本槽畔,在代碼中引入新的bug。
Layered APIs是為實(shí)現(xiàn)通過(guò)瀏覽器以可擴(kuò)展的方式實(shí)現(xiàn)和交付更高級(jí)別的api做的努力胁编。JS modules 是實(shí)現(xiàn)分層api的關(guān)鍵技術(shù):

  • 由于模塊是顯式導(dǎo)入的厢钧,因此需要通過(guò)模塊公開(kāi)分層api,從而確保開(kāi)發(fā)人員只為他們使用的分層api負(fù)責(zé)嬉橙。
  • 由于模塊加載是可配置的早直,所以分層api可以有一個(gè)內(nèi)置機(jī)制,用于在不支持分層api的瀏覽器中自動(dòng)加載polyfill憎夷。

modules 和 layered APIs 如何一起工作的細(xì)節(jié)我們還在制定當(dāng)中莽鸿,不過(guò)當(dāng)前的建議看起來(lái)像下邊這樣:

<script
  type="module"
  src="std:virtual-scroller|https://example.com/virtual-scroller.mjs"
></script>

這個(gè)<script>標(biāo)簽會(huì)從瀏覽器內(nèi)置的分層API集(std:virtual-scroller)或者從指向回滾到polyfill的url中去加載virtual-scrollerAPI。這個(gè)API可以做任何JS模塊在web瀏覽器中可以做的事情拾给。其中一個(gè)例子就是定義一個(gè)自定義<virtual-scroller>元素祥得,因此下面的HTML將可以按照你想要的方式逐步加強(qiáng)。

<virtual-scroller>
  <!-- Content goes here. -->
</virtual-scroller>

原文鏈接
如有錯(cuò)誤蒋得,歡迎指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末级及,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子额衙,更是在濱河造成了極大的恐慌饮焦,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窍侧,死亡現(xiàn)場(chǎng)離奇詭異县踢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)伟件,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)硼啤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人斧账,你說(shuō)我怎么就攤上這事谴返∩飞觯” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵嗓袱,是天一觀的道長(zhǎng)籍救。 經(jīng)常有香客問(wèn)我,道長(zhǎng)渠抹,這世上最難降的妖魔是什么蝙昙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮逼肯,結(jié)果婚禮上耸黑,老公的妹妹穿的比我還像新娘桃煎。我一直安慰自己篮幢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布为迈。 她就那樣靜靜地躺著三椿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪葫辐。 梳的紋絲不亂的頭發(fā)上搜锰,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音耿战,去河邊找鬼蛋叼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛剂陡,可吹牛的內(nèi)容都是我干的狈涮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸭栖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼歌馍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起晕鹊,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤松却,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后溅话,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體晓锻,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年飞几,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砚哆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡循狰,死狀恐怖窟社,靈堂內(nèi)的尸體忽然破棺而出券勺,到底是詐尸還是另有隱情,我是刑警寧澤灿里,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布关炼,位于F島的核電站,受9級(jí)特大地震影響匣吊,放射性物質(zhì)發(fā)生泄漏儒拂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一色鸳、第九天 我趴在偏房一處隱蔽的房頂上張望社痛。 院中可真熱鬧,春花似錦命雀、人聲如沸蒜哀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)撵儿。三九已至,卻和暖如春狐血,著一層夾襖步出監(jiān)牢的瞬間淀歇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工匈织, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浪默,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓缀匕,卻偏偏與公主長(zhǎng)得像纳决,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弦追,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 上一章介紹了模塊的語(yǔ)法岳链,本章介紹如何在瀏覽器和 Node 之中加載 ES6 模塊,以及實(shí)際開(kāi)發(fā)中經(jīng)常遇到的一些問(wèn)題...
    emmet7life閱讀 2,754評(píng)論 0 1
  • 問(wèn)答題47 /72 常見(jiàn)瀏覽器兼容性問(wèn)題與解決方案劲件? 參考答案 (1)瀏覽器兼容問(wèn)題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,754評(píng)論 1 92
  • 簡(jiǎn)單的嵌套查詢 舉例:查詢考試大于等于90分的學(xué)生信息 帶in的嵌套查詢 舉例:查詢參加考試的學(xué)生信息 帶not ...
    晟文刀閱讀 1,381評(píng)論 0 1
  • 說(shuō)不過(guò)就把評(píng)論里所有與他不利的評(píng)論都刪除了掸哑,雖然進(jìn)一步證明他心虛了,但因此證據(jù)也就無(wú)法保留了零远,也無(wú)法讓更多人見(jiàn)識(shí)到...
    掉命閱讀 324評(píng)論 0 1
  • 能夠擁抱的就別拉扯牵辣,能夠握緊的就別放了 01 人生總是有太多分別 ? 人生好像走到了一個(gè)十字路口摔癣,遇到一個(gè)人很難很...
    情諾未央閱讀 1,216評(píng)論 0 1