Preface
This is the last content of the ES6 notes series, and also the only feature that can only be used in the future
When is the future?
Perhaps when HTTP2 becomes widespread. But more likely, it will "not be usable" in the future either (still can only be used in build tools, existing only in "compile time")
1. AMD, CMD and CommonJS
AMD/CMD, some extended knowledge as follows:
CommonJS is a set of theoretical specifications (for example, the theoretical specification for js is ES), while SeaJS and RequireJS are both concrete implementations of the Modules part of CommonJS
CommonJS was formulated for js outside the browser (server side), so it uses synchronous module loading. SeaJS is an implementation of CommonJS, and while RequireJS is also an implementation of CommonJS, it uses asynchronous module loading, which is more suited to the browser's single-threaded environment
Summary: The Modules part of CommonJS proposed the theory of modular code management. To enable js to load modules, various implementations like RequireJS and SeaJS can be called modular script loaders
CMD: Common Module Definition, such as SeaJS
AMD: Asynchronous Module Definition, such as RequireJS
Both are a set of specifications for defining code modules, facilitating modular script loading and improving response speed
Differences between CMD and AMD:
CMD has nearby dependencies. Easy to use, dependencies can be fetched as needed within the module, no need to declare dependencies in advance, so there's some performance reduction (need to traverse the entire module to find dependencies)
AMD has前置 dependencies. Must strictly declare dependencies, for dependencies within logic (soft dependencies), solved through asynchronous loading and callback handling
(Quoted from [JS Programming Common Sense](/articles/js 编程常识/#articleHeader9))
If you've paid attention to JS modularization, you should be clear about the confused relationship between these three. ES6 modules hope to end this confusion through standards
2. ES6 Module Syntax
1. Module Scope
module introduces module scope, with the following characteristics:
-
Currently (
2016/1/312016/10/29) no browser supports ES6 modules (possibly such module loading mechanism is not suitable for browser environment), using tools like webpack can integrate all imported content into one file -
ES6 modules are in strict mode by default, whether or not you add
'use strict'; -
Supports renaming during import/export,
import/export {api as newApi}, renaming during import mainly solves naming conflicts, renaming during export can implement aliases ($andjQuery) -
Supports default import/export, can import CommonJS and AMD modules
-
Can only use
import/exportat the outermost scope of the module, and cannot use in conditional statements
Summary: Promotes strict mode; compatible with CommonJS and AMD; just a simple static module mechanism, doesn't solve problems like on-demand loading
Renaming during import/export, examples as follows:
// Rename during import, solve naming conflicts
import {flip as flipOmelet} from "eggs.js";
import {flip as flipHouse} from "real-estate.js";
// Rename during export, implement aliases
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
2. import
import {api1, api2...} from 'xxx.js' syntax, characteristics as follows:
-
Supports partial api import (don't import unnecessary function interfaces, of course,
xxx.jsis fully loaded, partial import is just scope control) -
If
xxx.jsalso hasimportstatements, will load and execute depth-first -
Executed modules will be ignored, avoiding forming circular references
-
Supports default import, used to support importing CommonJS and AMD packages (
defaultis theexportobject),import api from 'xxx.js'is equivalent toimport {default as api} from 'xxx.js' -
Supports importing module objects,
import * as apis from 'xxx.js',*represents everythingexported inxxx.js, integrates everything exported fromxxx.jsinto theapisobject, access throughapis.xx
Summary: Loading mechanism is similar to CSS's @import, handling of circular dependencies is also similar; also compatible with CommonJS and AMD
At the scope level supports partial import, useful, but not very meaningful, better配合 with build tools for "pruning" (tree shaking) during compilation
3. export
export {api1, api2...} syntax, characteristics as follows:
-
No need to declare on the first line, can
exportat any position in the module's outer scope -
Can declare multiple
exports, but must ensure api names have no duplicates, duplicate names may cause errors -
Supports default export,
export default apiorexport {api as default} -
Supports aggregated export,
export {api1, api2...} from 'xxx.js'is equivalent toimport + export, butexport fromwon't introduce each api variable into the current module scope (imports then directly exports, cannot reference) -
The api list exported by
exportmust be in literal form, cannot traverse an array to export array elements
Summary: Organizes export list during loading, so can export at any position in outer scope; supports aggregation, extracts parts from various third-party modules and integrates them; static limitation, doesn't allow dynamic export
Examples as follows:
// Default export
let myObject = {
field1: value1,
field2: value2
};
export {myObject as default};
// Equivalent to
export default {
field1: value1,
field2: value2
};
// Aggregated export
// Import "sri-lanka" and re-export part of what it exports
export {Tea, Cinnamon} from "sri-lanka";
// Import "equatorial-guinea" and re-export part of what it exports
export {Coffee, Cocoa} from "equatorial-guinea";
// Import "singapore" and export everything it exports
export * from "singapore";
3. Module Execution Mechanism
ES6 standard doesn't specify the concrete module loading mechanism, left to the final implementation to decide, but clearly specifies the module execution mechanism, divided into 4 steps
- Syntax Parsing
Check for syntax errors
- Loading
Recursively load everything imported, how exactly to load, not specified, completely left to the final implementation to decide
- Linking
Create module scope, and stuff everything imported into the scope
If import errors, it will trigger an error, specific behavior unknown (because no browser has yet passed step 2)
- Runtime
Execute every statement of every module, at this point encounter import/export and ignore them, because module-related processing has ended
Static Limitations
-
Can only use
import/exportat the module's outermost scope, cannot use in conditional statements, nor in function scope -
Identifiers exported by
exportmust be in literal form (must have corresponding declaration in source code), cannot traverse an array and then export a bunch of things -
Module objects are frozen, cannot add
polyfill-style new features byhacking module objects -
All dependencies of a module must be loaded, parsed and linked before module code execution, there's no syntax for on-demand lazy loading through
import -
Errors produced by
importing modules have no corresponding recovery mechanism. If a module fails to load or link, no modules will execute, and cannot catchimporterrors -
Cannot execute other code before module loads dependencies, this means cannot control the module's dependency loading process
Because these limitations exist, so possibly after HTTP2 becomes widespread, ES6 module mechanism still may not rise in browsers, like CSS's @import, usable, but nobody wants to use it
4. HTTP2 and Modularization
In the HTTP1.1 environment, to reduce HTTP request count, all modularization solutions ultimately rely on build tools to integrate into a single file
But HTTP2 brings some changes, perhaps able to change this engineering process, such as Multiplexed stream and Server Push:
Http2 connections can carry dozens or hundreds of multiplexed streams, multiplexing means data packets from many streams can be mixed together and transmitted through the same connection, two different trains mixed together for transmission, when reaching the destination, they are separated and reassembled into two different trains.
Client requests a resource X, server judges that perhaps the client also needs resource Z, pushes resource Z to the client without asking the client in advance, after client receives it, can cache it for later use.
(Quoted from Introduction to Http 2.0 Protocol)
Multiplexed streams level the advantage of file merging, server push helps solve deep import problems, so ES6 modules may rise in browser environments
HTTP2 has important significance for the modularization process, providing opportunities to maintain modularization in production environments, JS, CSS and even other resources may welcome true modularization
P.S. For more details about HTTP2, please check https://github.com/bagder/http2-explained
5. Current Status of ES6 Modules
As the various milestones of the roadmap are completed, browsers will be able to implement them. See the following trackers for the current status of the main browsers:
IE/Edge: Under Consideration
Firefox: In progress
Chrome: In progress
Webkit: Meta Bug
(Quoted from https://github.com/whatwg/loader)
For more information about ES6 module loaders, please follow this repo, ES6 specification doesn't specify the concrete implementation of loading, so browsers are all stuck on loader implementation
References
- "ES6 in Depth": Free e-book provided by InfoQ Chinese site
No comments yet. Be the first to share your thoughts.