Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Example Analysis of JS Front-end Modularization Specification

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article will explain in detail the example analysis of the JS front-end modularization specification. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

Script tag

In fact, the most original way to load JavaScript files is the Script tag. If you regard each file as a module, then their interfaces are usually exposed in the global scope, that is, defined in the window object, the interface calls of different modules are in a scope, and some complex frameworks will use the concept of namespaces to organize the interfaces of these modules.

Disadvantages:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Pollution global scope

The developer must subjectively resolve the dependency between the module and the code base

Files can only be loaded in the order in which script tags are written

In large projects, various resources are difficult to manage, and long-term accumulated problems lead to confusion in the code base.

By default, browsers load JavaScript scripts synchronously, meaning that the rendering engine stops when it encounters a tag, waits until the script is executed, and then continues to render down. If it is an external script, you must also include the time when the script is downloaded.

If the script is large, it will take a long time to download and execute, so the browser will be blocked and the user will feel that the browser is "jammed" and there is no response. This is obviously a bad experience, so browsers allow scripts to load asynchronously.

Add a defer or async attribute to the tag, and the script loads asynchronously. When the rendering engine encounters this line of command, it starts downloading the external script, but instead of waiting for it to download and execute, it executes the following commands directly.

Defer: it will not be executed until the whole page is rendered normally in memory; when there are multiple scripts, it will be executed sequentially.

Async: once downloaded, the rendering engine interrupts the rendering and executes the script before continuing the rendering. When there are multiple scripts, there is no guarantee that they will be executed in order

To sum up: defer is "rendering before execution", and async is "execution after download".

CommonJS specification (synchronous loading module)

Node.js is the hottest implementation of CommonJS specification at present.

Load the dependent modules synchronously through the require method, and export the data that needs to be exposed through exports or module.exports.

CommonJS specification includes module (modules), package (packages), system (system), binary (binary), console (console), coding (encodings), file system (filesystems), socket (sockets), unit test (unit testing) and so on.

Create a module

In Node.js, it is very simple to create a module. A file is a module.

/ / module.js module var name = "Echoyya"; / / todo something... Exports.name = name load module

Use the require function to load the module (that is, the module.exports object of the dependent module).

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Load modules by path

Load the module by looking up the node_modules directory

Load cache: Node.js is cached based on the actual filename, rather than the parameters provided by require (), such as require ('express') and require ('. / node_modules/express'), which are loaded twice and will not be loaded repeatedly, although the two parameters are different, but the parsed file is the same.

The core module has the highest load priority, in other words, if a module conflicts with its name, Node.js will always load the core module.

Export module

Exports. Attribute = value

Exports. Method = function

Node.js provides an exports variable for each module, pointing to module.exports. As opposed to each module header, there is a command like this: var exports = module.exports

Exports object and module.exports object refer to the same memory space, and module.exports object is the real exposed object.

The exports object is a reference to the module.exports object, which cannot change the direction, but can only add properties and methods. If you directly change the direction of the exports, it is tantamount to severing the connection between the exports and the module.exports and returning an empty object.

Console.log (module.exports = = exports); / / true

Other uses:

/ / singleobjct.js function Hello () {var name; this.setName = function (thyName) {name = thyName;}; this.sayHello = function () {console.log ('Hello' + name);};} exports.Hello = Hello

At this point, get the Hello object require ('. / singleobject'). Hello, which is slightly redundant and can be simplified in the following ways.

/ / hello.js function Hello () {var name; this.setName = function (thyName) {name = thyName;}; this.sayHello = function () {console.log ('Hello' + name);};} module.exports = Hello

You can get this object directly:

/ / gethello.js var Hello = require ('. / hello'); hello = new Hello (); hello.setName ('Yu'); hello.sayHello (); characteristics of CommonJS

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Synchronous loading mode is suitable for the server side, because the modules are placed on the server side, and the module loads faster for the server side, so it is not suitable for use in the browser environment, because synchronization means blocking loading.

All code runs in the module scope and does not pollute the global scope.

The module can be loaded multiple times, but it will only be run once on the first load, and then the run results will be cached and loaded later, and the cached results will be read directly.

The order in which modules are loaded, in the order in which they appear in the code.

AMD (Asynchronous Module Definition)

The module is loaded asynchronously, and the loading of the module does not affect the operation of the following statements. All statements that depend on this module are defined in a callback function, which will not run until the load is complete. Advocate dependence preposition

Require.js is the hottest implementation of AMD specification at present.

AMD also uses require statements to load the module, but unlike CommonJS, it requires two parameters: require ([module], callback)

[module]: is an array, and the members are the modules to be loaded

Callback: callback function after successful loading

Require (['math'], function (math) {math.add (2,3);}); create module

The module must be defined with the define () function.

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

If one module does not depend on other modules. It can be defined directly in the define () function.

/ / math.js define (function () {var add = function (xonomy) {return xperiy;}; return {add: add};})

If this module depends on other modules, then the first argument to the define () function must be an array indicating the dependencies of the module. When the require () function loads the test module, the myLib.js module loads first.

/ test.js define (['myLib'], function (myLib) {function foo () {myLib.doSomething ();} return {foo: foo};}); load specification module / / main.js require ([' math'], function (math) {alert (math.add);}); load non-standard module

Theoretically, the module loaded by require.js must be defined by the define () function in accordance with the AMD specification. But in fact, although there are already some popular function libraries (such as jQuery) that conform to the AMD specification, more libraries do not. So how can require.js load irregular modules?

Before such modules are loaded with require (), some of their characteristics are defined using the require.config () method.

For example, neither underscore nor backbone is written in the AMD specification. If you want to load, you must first define their characteristics.

Require.config ({shim: {'underscore': {exports:' _'}, 'backbone': {deps: [' underscore', 'jquery'], exports:' Backbone'})

Require.config () accepts a configuration object that has a shim property that is specifically used to configure incompatible modules. Each module needs to be defined:

Exports: the name of the output variable, indicating the name of the external call to this module

Deps: array that represents the dependencies of the module.

Plug-ins such as jQuery can also be defined as follows:

Shim: {'jquery.scroll': {deps: [' jquery'], exports: 'jQuery.fn.scroll'}} AMD characteristics

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

AMD allows the output module to be compatible with CommonJS

Asynchronous parallel loading does not block DOM rendering.

It is highly recommended to rely on prefix, that is, early execution (pre-execution), which is completed before the module is used.

CMD (Common Module Definition)

CMD is a general-purpose module loading, and the problem to be solved is the same as AMD, except that the timing of the execution of dependent modules is different, advocating proximity dependence.

Sea.js is an implementation representative library of CMD specification.

The definition module uses the global function define to receive a factory parameter, which can be a function, an object or a string

1. When factory is a function, there are three parameters, function (require, exports, module):

Require: the function is used to obtain the interface require provided by other modules (module identification ID)

Exports: object is used to provide module interface to the outside

Module: object that stores the properties and methods associated with the current module

/ / define a.js module define (function (require, exports, module) {var $= require ('jquery.js') exports.price= 200;}); / / b.js load module const a = require ('. / a.js')

2. When factory is an object or string, the interface of the module is the object or string. For example, you can define a JSON data module:

Define ({"foo": "bar"})

3. Define the module through the string template:

Define ('I am a template.My name is {{name}}.'); the difference between AMD and CMD

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

AMD is executed in advance and CMD is deferred.

AMD is dependent on the front, CMD is dependent on the nearest.

/ / AMD define (['. / averse,'. / b'], function (a, b) {/ / declare the dependent module a.doSomething () / / when defining a module. B.doSomething () / /.... }) / / CMD define (function (require, exports, module) {var a = require ('. / a') a.doSomething () / /. Var b = require ('. / b') / / you can go to require b.doSomething () / /.}) UMD (Universal Module Definition) when using a module.

UMD is a blend of AMD and CommonJS

The implementation of UMD is simple:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

First determine whether the Node.js module is supported (whether exports exists or not), and use the Node.js module mode if it exists.

Then determine whether to support AMD (whether define exists or not), and use AMD to load the module if it exists.

If neither of the first two exists, expose the module to the global (window or global).

(function (window, factory) {if (typeof exports = 'object') {module.exports = factory ();} else if (typeof define =' function' & & define.amd) {define ([], factory);} else {window.eventUtil = factory ();}}) (this, function () {return {};}); ES6 modularization

The design idea of the ES6 module is to be static as much as possible, so that the dependency of the module and the variables of input and output can be determined at compile time.

In ES6, import refers to the module and uses export to export the module. Through the babel project, the ES6 modules that are not directly supported by the host environment (browsers, Node.js) will be compiled into CommonJS of ES5. So Babel is actually translating an unsupported import/export into a currently supported require/exports.

/ / Import import Vue from 'vue' import App from'. / App' / / Export function v1 () {} function v2 () {...} export {v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion}; export function multiply () {...}; export var year = 2018; export default. Modular specification large summary CommonJSAMDCMDES6 reference module requirerequirerequireimport exposure interface module.exports | | return value of exportsdefine function returnexportsexport loading mode runtime loading, synchronous loading parallel loading, early execution, asynchronous loading parallel loading, on demand execution, asynchronous loading compilation time loading, asynchronous loading implementation module specification NodeJSRequireJSSeaJS native JS applicable server browser server / browser problem regression: the difference between "require" and "import"

Having said so much, I would like to return to the question mentioned at the beginning of the article. There is a difference between "require" and "import" in the introduction of modules, which can be roughly divided into the following aspects (which may not be very comprehensive):

The difference in writing

There are only three simple ways to write require/exports:

Const fs = require ('fs') exports.fs = fs module.exports = fs

Import/export is written in a variety of ways:

Import fs from 'fs' import {default as fs} from' fs' import * as fs from 'fs' import {readFile} from' fs' import {readFile as read} from 'fs' import fs, {readFile} from' fs' export default fs export const fs export function readFile export {readFile, read} export * from 'fs' input value difference

The variable input by require. The basic type data is assigned, and the reference type is shallow copy, which can be modified.

The variables entered by import are read-only, and if the input an is an object, object properties are allowed to be overwritten.

Import {a} from'. / xxx.js' a = {}; / / Syntax Error:'a'is read-only; a.foo = 'hello'; / / legal operation execution sequence

Require: does not have the promotion effect, in the end which module loads, only the runtime knows.

Const path ='. /'+ fileName; const myModual = require (path)

Import: with a lifting effect, it will be promoted to the head of the entire module, which is executed first. The execution of import predates the call to foo. The essence is that the import command is executed at compile time, before the code runs.

Foo (); import {foo} from 'my_module'

Import () function: the ES2020 proposal is introduced to support dynamic loading of modules. The import () function takes a parameter that specifies the location of the module to be loaded. The parameter format is the same as the import command. The main difference between the two is that import () is dynamically loaded. It can be used for demand loading, conditional loading, dynamic module path, and so on.

It is executed at run time, that is, when it runs to this sentence, the specified module is loaded and a Promise object is returned. After import () successfully loads the module, the module acts as an object and as a parameter to the then method. You can use objects to deconstruct assignments and get the output interface.

/ / load button.addEventListener on demand ('click', event = > {import ('. / dialogBox.js'). Then ({export1, export2} = > {/ / export1 and export2 are both output interfaces of dialogBox.js, deconstructing to get / / do something... ) .catch (error = > {})}); / / conditional loading if (condition) {import ('moduleA'). Then (...);} else {import (' moduleB'). Then (...);} / dynamic module path import (f ()). Then (...); / / load different modules depending on the result returned by the function f. Using expressions and variables

Require: obviously you can use expressions and variables

Let a = require ('. / a.js') a.add () let b = require ('. / b.js') b.getSum ()

Import executes statically, and cannot use expressions and variables, because these are syntax structures that can only get results at run time.

/ / error reporting import {'f' + 'oo'} from' my_module'; / / error reporting let module = 'my_module'; import {foo} from module; / / error if (x = 1) {import {foo} from' module1';} else {import {foo} from 'module2';}

The essential difference between require/exports and import/export is actually the difference between CommonJS specification and ES6 modularization.

There are three major differences between them.

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

The CommonJS module outputs a copy of the value, and the ES6 module outputs a reference to the value.

The CommonJS module is loaded at run time, and the ES6 module is the compile-time output interface.

The require () of the CommonJS module is the synchronous loading module, and the import command of the ES6 module is loaded asynchronously, with an independent module dependent parsing phase.

The second difference is caused by the fact that CommonJS loads an object (that is, the module.exports property) that is generated only after the script has been run. While the ES6 module is not an object, its external interface is only a static definition, which will be generated in the code static parsing phase.

CommonJS: loading at run time

You can only determine the dependencies of the module at run time, as well as the input and output variables. A module is an object, and you must find the object properties when you enter it.

/ / CommonJS module let {stat, exists, readfile} = require ('fs'); / / equivalent to let _ fs = require (' fs'); let stat = _ fs.stat; let exists = _ fs.exists; let readfile = _ fs.readfile

ES6: load at compile time or statically

The ES6 module is not an object, but the output code is explicitly specified by the export command and entered by the import command.

You can finish loading the module at compile time, and load only the methods you need when referencing, but not other methods. It is more efficient than the way CommonJS modules are loaded.

Import {stat, exists, readFile} from 'fs'; 's article on "sample Analysis of JS Front-end Modularization Specification" ends here. I hope the above content can be helpful to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report