当前位置: 首页 >> 趣闻中心 >> 国考面试,梦醒时分,好看的小说-火车品牌-优惠购信息-火车沿线本地新闻 >> 正文

国考面试,梦醒时分,好看的小说-火车品牌-优惠购信息-火车沿线本地新闻

2019年05月21日 09:19:57     作者:admin     分类:趣闻中心     阅读次数:159    

原文:《Using JavaScript modules on the web》 https://developers.google.com/web/fundamentals/primers/modules

译者序

JS modules,即ES6的模块化特性,经过 可以完成不经过打包直接在浏览器中import/export,此玩法的确让人眼前一亮。

先看看 的兼容性。现在只需较新版别的chrome/firefox/safari/edge支撑此特性,看来要遍及运用还负重致远。下面跟着这篇文章深化了解一下涨涨姿态。

本文将介绍JS模块化;怎样在不经过打包的状况下直接在浏览器中运用模块化;以及Chrome团队在JS模块化的优化和遍及上正在做的一些工作。

JS模块化

你或许用过命名空间、CommonJS或许AMD标准进行JS模块化,但一切的这些模块处理计划万变不离其宗:引进(import)其他模块,作为一个模块输出(export)。假如说命名空间、CommonJS、AMD都是野路子,那ES6的JS modules则是正规军,将模块化语法一致起来(一统江湖,千秋万代)。

在JS modules中,你可以运用 export要害字输出任何东西: const、 function等。

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

然后你可以用 import要害字从另一个模块中引进来。下面代码将lib模块中的 repeat和 shout函数引到了咱们的主模块main中。

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

你也可以经过 default要害字,输出一个默许值。

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

而经过上面的 default输出的模块,在引进时可以用其他任何变量名。

// main.mjsimport shout from './lib.mjs';// ^^^^^

模块脚本与惯例脚本有所差异:

  • 模块脚本默许敞开了严厉形式
  • 不支撑HTML风格的注释
  • 模块具有词法尖端作用域。也便是说在模块中 varfoo=42;并不会像传统脚本相同,创立一个全局变量 foo,可以经过 window.foo拜访。
  • 新的 import和 export语法仅限于在模块脚本中运用,不能用在惯例脚本中。

正因为这些差异,模块脚本和传统脚本明显需求各自不同的解析方法。因而JS解析器需求标识出哪些脚本属所以模块类型的。

浏览器怎么辨认模块脚本

你可以经过设置

那些支撑 type=module的浏览器会疏忽掉 nomodule的脚本,而不兼容也会高雅降级,履行fallback.js。

译者注:亲测在IE7+到edge,oppo手机自带的浏览器都可以降级而履行fallback.js。不过加载fallback的一起,也会把index.mjs一起加载,而支撑module的浏览器则不会加载fallback。

IE系列均会履行fallback.js

加载fallback的一起,也会把index.mjs一起加载

而支撑module的浏览器则只会加载模块

有没想过别的一个优点:已然浏览器可以辨认module,那它必定也可以支撑ES67的其他特性,如箭头函数、async-await。你不需求为这些特性进行babel编译,现代浏览器跑着更小和最大部分未编译的模块化代码,而不兼容的则运用nomodule的降级代码。

浏览器加载方面的异同:模块脚本vs传统脚本

上面介绍了模块脚本和传统脚本在言语层面的异同,除此之外,在浏览器加载过程中也有所不同。

相同的模块脚本只会履行一次,而传统脚本会声明屡次。


模块脚本跨域需求加跨域头

模块脚本及其依靠是经过CORS来获取的,也便是说模块脚本一旦跨域就需求加上恰当的返回头,比方 Access-Control-Allow-Origin:*。而众所周知,传统脚本则不需求(译者注:还记得传说中的JSONP吗)。

async特点对内联脚本有用


加了async特点会使得脚本在下载过程中不堵塞DOM烘托,而下载完成后当即履行,两个async脚本之间的履行时序不确定,履行机遇也不确定,有或许在domContentLoaded之前或许之后。但这一特点对传统的内联脚本是无效的,而对模块的内联脚本却是有用的。

关于 .mjs文件后缀

你或许会对前面的 .mjs后缀感到猎奇,可是在互联网的国际里,文件后缀并不重要,只需服务器下发的MIME类型( Content-Type:text/javascript)正确就可以。浏览器是经过script标签上的type特点来辨认模块脚本的,而不是后缀名。

所以不管运用 .js仍是 .mjs都是可以的。可是咱们仍是主张运用 .mjs,原因有两个:

  1. 在开发的时分,可以不需求看代码,经过后缀名十分直观地看出哪些是模块脚本。
  2. nodejs中,ES6的模块化特性仍在实验性阶段,而该特性只支撑 .mjs后缀的脚本。

模块资源标识符 - module specifier

在import一个模块时,后边的相对或绝对途径字符串称为module specifier或import specifier,也便是模块资源途径。

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

浏览器关于模块资源途径做了一些约束。不支撑相似下面这种只需模块名或部分文件名的资源途径(称之为bare module specifiers)。这样的约束是为了今后浏览器在支撑自定义模块加载器之后,加载器可以自行决定bare module specifiers的解析方法。

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

现在,模块资源途径有必要是完好的URL,或许以 /, ./, ../最初的相对URL

// 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';

模块script默许是defer

传统脚本的加载和解析会堵塞html的解析,可以经过添加 defer特点处理(让脚本加载和html解析并行)

但这儿想通知你的是,模块脚本默许具有defer的并行功用,因而无需弄巧成拙加上defer特点。还有不只仅只需主模块与html解析并行,其他子模块也相同。

JS模块化的其他特性

动态引进: import()

咱们之前只是用到了静态的 import,它需求在首屏就把悉数模块资源都下载下来。但有时分按需加载或异步加载会更为合理,这有助于进步初次加载时刻,而 import()可以用来处理这个问题。


不像静态 import只能用在 "相同,动态 import()也可以用在一般的script。详细可以看下咱们关于动态import的文章。

NOTE: Webapck自己完成了一套 import()计划,可以动态将import()进去的模块抽离出来,生成独自的文件。

import.meta

另一个和JS modules相关的新特性是 import.meta,它能供给关于当时模块的meta信息。精确的meta信息并不是ECMAScript标准指定的部分,它取决于宿主环境。在浏览器拿到的meta信息和在nodejs里边拿到的是有差异的。

下面的比方中,图片的相对途径默许是依据HTML所在位置来解析的,但经过 import.meta.url可以完成依据当时模块来解析。

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

功用优化主张

持续运用打包东西

经过模块脚本,开发时咱们可以无需再用webpack、Rollup、Parcel等打包东西就可以享用原生的模块化福利,在以下场景主张可以直接运用原生的模块脚本:

  1. 开发环境下
  2. 不超越100个模块且相对较浅的依靠层级联系(小于5)的小型web运用

可是,咱们在功用瓶颈剖析中发现,加载一个模块化库(大约300个模块),经过打包的功用数据要比未经过打包直接运用原生模块脚本的好。

其间一个原因是 import/ export语法是可以静态剖析的,因而打包东西在打包过程中就可以进行静态剖析并移除冗余未运用的模块。从这可以看出,静态的 import/ export不只只是仅语法特性,还具有要害的东西特点(可静态剖析)!

咱们的全体主张是持续运用打包东西进行上线前的模块打包处理。究竟从某种程度上,打包可以协助你尽或许削减代码体积,用户不必要加载无用的脚本,更有利于页面功用。

开发者东西的代码覆盖率检查能协助你检测源码中是否存在无用代码。咱们一起也主张经过代码切割对模块进行合理拆分,以及推迟加载非首屏要害途径的脚本。

打包与运用模块脚本的权衡取舍

通常在web开发范畴,一切计划都有利害,需求权衡取舍。与加载一个未经过代码拆分的打包脚本比较,运用模块脚本或许会下降初次加载功用(cold cache),可是可以进步用户再次加载(warm cache)的速度。比方关于总巨细200KB的代码,在修正一个细颗粒化的模块之后,那么用户只需求更新有改变的代码,这总比从头加载一切代码(打包脚本)要强。

假如相关于初次拜访体会来说,你更重视用户再次拜访体会,而且你的运用不超越数百个细颗粒化模块的话,你无妨测验下运用模块脚本,经过功用数据比照之后再做出终究的挑选。

浏览器工程师们正尽力进步模块脚本的功用,咱们期望模块脚本今后可以适用于更多的运用场景。

运用细颗粒化的模块

尽或许让你的代码以细颗粒化的模块进行安排。当在开发时,每个模块最好不要输出过多的内容。

下面的 ./util.mjs模块,输出了 drop pluck和 zip三个函数。

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

假如你的代码只是只需求 pluck,你或许会这样引进:

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

在这种状况下,假如没有构建打包编译,浏览器会仍是会下载、解析和编译整个 ./util.js模块,即便只只是需求其间一个export。

假如 pluck不与 drop和 zip有引证或依靠联系的话,最好仍是将它独立成一个模块 ./pluck.mjs。以到达无需加载其他无用函数的意图。

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

这不只可以让你的源码简练,还可以削减对打包东西(移除冗余代码)的依靠。假如在你的运用中其间一个模块从未被 import过,那么浏览器就不会去下载。而那些真实有用的模块则会被浏览器缓存起来。

此外,运用细颗粒化的模块也有助于对接未来的浏览器原生打包功用。

预加载模块

经过 你可以进一步优化模块加载。浏览器会预加载乃至预解析和编译这些模块及其依靠。


这关于有杂乱依靠联系模块的运用尤为重要。没有 rel="modulepreload",浏览器需求宣布多个HTTP恳求来核算出整个依靠联系。而假如你把一切依靠模块经过 rel="modulepreload"提早通知浏览器,那么浏览器则无需再渐进式地去核算。

选用HTTP/2协议

HTTP/2支撑多路复用,多个恳求及呼应信息可以一起进行传输,这有助于进步模块树的加载功率。

Chrome团队还预研了服务器推送——另一个HTTP/2特性,是否可以作为布置高度模块化运用的一个可行计划。但结局令人绝望,HTTP/2的服务器推送比幻想中要难以运用,而且web服务器及浏览器的对其完成现在并没有针对高度模块化web运用进行优化。另一方面,服务器很难只推送未被缓存的资源。假如经过奉告服务器完好的用户缓存状况来处理这个问题的话,又存在隐私走漏危险。

不管怎么,选用HTTP/2协议吧!只需记住现在HTTP/2的服务器推送现在还不能作为一个好的处理计划。

现在的运用率

JS modules正在缓慢地被接收运用。咱们的运用核算显现只需0.08%(不包含动态 import()或许worklets)的页面现在运用了

JS Modules未来的开展

Chrome团队正在经过不同的方法,致力于进步依据JS modules的开发体会。下面罗列其间的几种。

更高效、确定性更高的模块解析算法

咱们提交了一版关于现在模块解析算法的优化。新算法现在现已被一起列入了HTML标准和ECMASciprt标准,而且已在Chrome 63版别中完成。期望这项优化可以在更多的浏览器中落地。

新算法更快更高效,旧算法在核算依靠图谱(dependency graph)巨细的时刻杂乱度为O(n²),在Chrome中的完成也是相同。而新算规律进步至O(n)。

此外,新算法在报解析过错时愈加精确。假如一个依靠图谱中有多个过错,那么依据旧算法,每次履行都会报不同的解析过错。这给开发调试带来不必要的困难。新算规律确保每次履行都会报相同的解析过错。

Worklets 和 web workers

Chrome完成了worklets,答应web开发者自定义那些在浏览器底层的硬编码逻辑。现在开发者可以将一个JS模块引进到烘托管道(rendering pipeline)或许音频处理管道。

Chrome65版别支撑了 PaintWorklet,也称为CSS制作API(the CSS Paint API),用于操控怎么制作一个DOM元素。

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

Chrome66版别支撑了 AudioWorklet,答应开发者注入自定义的音频处理代码。一起这个版别开端了 AnimationWorklet的公测,开发者可以发明视差翻滚作用(scroll-linked)以及其他高功用程序动画(procedural animations)。

终究, LayoutWorklet,又称为CSS布局API(the CSS Layout API)已在Chrome67版别中完成。

咱们正在对Chrome中的web workers支撑传入模块脚本。你可以经过输入 chrome://flags/#enable-experimental-web-platform-features敞开这个特性。

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

在shared workers和service workers传入模块脚本也行将支撑。

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

包名映射表 - Package name maps

在nodejs/npm中,咱们常常会经过它们的包名引进模块,比方:

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

依据现行的HTML标准,相似上述的包名写法(bare import specifiers)会抛出反常。咱们提交的“包名映射表”提案将会支撑上述写法(包含在出产环境)。该映射表(JSON格局)将协助浏览器将包名转换为完好资源途径(full URLs)。

包名映射表现在仍处于提案阶段(proposal stage)。

Web packaging:浏览器原生打包

Chrome loading团队正在探究一种原生的web打包格局(下称为web packaging),作为一种新形式来分发web运用。web packaging的首要特性如下:

  1. Signed HTTP Exchanges:可以让浏览器信赖某个HTTP恳求对(request/response)的确是来自于所声明的源服务器。
  2. Bundled HTTP Exchanges:是多个恳求对的调集,不要求傍边的每个恳求都进行签名(signed),只需带着某些元数据(metadata)用于描绘怎么将恳求束作为一个全体来解析。

两者结合起来,这种web打包格局就可以将多个同源资源安全地整合到一个HTTP GET相应中。

市面上的打包东西如webpack、Rollup、Parcel,都会将多个模块终究打包成一个或少量几个bundle,这会导致源码中进行的模块拆分在上线后就丧失了它的含义。那么经过原生打包,浏览器可以将bundle反解成原样。

简略来说,你可以把一个HTTP恳求对包(Bundled HTTP Exchange)理解为一个资源文件包,它可以经过目录表(manifest)随意拜访,而且里边的资源可以被高效地缓存以及依据相对优先级的凹凸来符号。有了这个机制,原生模块可以进步开发调试的体会。当你在Chrome开发者东西检查资源时,浏览器会精准定位到原生的模块代码中,而不需求杂乱的source-map。

Chrome现已完成了一部分提案(SignedExchanges),可是打包格局(bundling format)以及在高度模块化app中的运用仍在探究阶段。

Layered APIs

移植新的功用和API到浏览器中无可避免会带来持续性的保护本钱以及运转本钱。每一个新特性都会污染浏览器的命名空间,添加发动开支,而且也增大引进bug的或许性。Layered APIs的意图是以一种更具扩展性的方法经过浏览器来完成或移植一些高档API。而模块脚本是完成Layered APIs的一项要害技术。

  • 因为模块是显式引进的,所以经过模块来引进layered APIs可完成按需运用(不会默许内置)。
  • 模块的加载源可自定义,因而layered APIs完成了一套主动加载polyfill(当不支撑时)的机制。

模块脚本和layered APIs怎么协同运作,详细细节仍在拟定中,但现在的协议如下:

 

这个模块脚本引进了 virtual-scrollerAPI,假如浏览器支撑则会直接读取内置layered APIs调集(std:virtual-scroller),反之则网络加载对应的polyfill。

译者:关于Layered APIs更多的中文介绍 https://zhuanlan.zhihu.com/p/37008246

除非特别注明,本文『国考面试,梦醒时分,好看的小说-火车品牌-优惠购信息-火车沿线本地新闻』来源于互联网、微信平台、QQ空间以及其它朋友推荐等,非本站作者原创。 本站作者admin不对本文拥有版权,如有侵犯,请投诉。我们会在72小时内删除。 但烦请转载时请标明出处:“本文转载于『火车品牌-优惠购信息-火车沿线本地新闻』,原文地址:http://www.railerband.com/articles/2320.html