이 기사는 JS의 프런트엔드 모듈화에 대한 자세한 분석 및 비교를 제공합니다. 필요한 친구가 참고할 수 있기를 바랍니다.
개발 중에는 모듈을 가져올 때 require
및 import
가 자주 사용됩니다. require
和import
;
导出模块时使用module.exports/exports
或者export/export default
;
有时候为了引用一个模块会使用require
奇怪的是也可以使用import
????它们之间有何区别呢?
于是有了菜鸟解惑的搜喽过程。。。。。
允许模块通过require方法来同步加载所要依赖的其他模块,然后通过exports或module.exports来导出需要暴露的接口。
使用方式:
// 导入 require("module"); require("../app.js"); // 导出 exports.getStoreInfo = function() {}; module.exports = someValue;
因为模块都放在服务器端,对于服务端来说模块加载时
而对于浏览器端,因为模块都放在服务器端,加载的时间还取决于网速的快慢等因素,如果需要等很长时间,整个应用就会被阻塞。
因此,浏览器端的模块,不能采用"同步加载"(CommonJs),只能采用"异步加载"(AMD)。
优点:
缺点:
?为什么浏览器不能使用同步加载,服务端可以?
同步加载方式不适合在浏览器环境中使用,同步意味着阻塞加载,浏览器资源是异步加载的
不能非阻塞的并行加载多个模块
简单容易使用
服务器端模块便于复用
参照CommonJs模块代表node.js的模块系统
采用异步方式加载模块,模块的加载不影响后面语句的运行。所有依赖模块的语句,都定义在一个回调函数中,等到加载完成之后,回调函数才执行。
使用实例:
// 定义 define("module", ["dep1", "dep2"], function(d1, d2) {...}); // 加载模块 require(["module", "../app"], function(module, app) {...});
加载模块require([module], callback);
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback是加载成功之后的回调函。
优点:
适合在浏览器环境中异步加载模块
可以并行加载多个模块
缺点:
提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
不符合通用的模块化思维方式,是一种妥协的实现
实现AMD规范代表require.js
모듈을 사용하세요. /exports
또는 export/export default
;
require
를 사용하는데, 이상하게도 import도 사용할 수 있습니다.
? ? ? ? 그들 사이의 차이점은 무엇입니까?
define(function(require, exports, module) { var a = require('./a'); a.doSomething(); // 依赖就近书写,什么时候用到什么时候引入 var b = require('./b'); b.doSomething(); });
모듈이 서버 측에 배치되기 때문에 서버 측의 경우 모듈이 로드될 때
그리고 브라우저 측의 경우 모듈이 서버 측에 배치되어 로딩 시간은 네트워크 속도와 같은 요인에 따라 달라집니다. 오랜 시간 동안 기다려야 하는 경우 전체 애플리케이션이 차단됩니다.
따라서 브라우저 측 모듈은 "동기 로딩"(CommonJs)을 사용할 수 없고 "비동기 로딩"(AMD)만 사용할 수 있습니다.
동기 로딩 방식은 브라우저 환경에서 사용하기에 적합하지 않습니다. 동기화는 로딩을 차단한다는 것을 의미합니다.
🎜🎜🎜 여러 파일을 차단하지 않고 병렬로 로드할 수 없습니다. 모듈🎜🎜🎜🎜🎜🎜간단하고 사용하기 쉽습니다🎜🎜🎜🎜서버측 모듈은 재사용이 쉽습니다🎜🎜🎜🎜🎜🎜node.js의 모듈 시스템을 표현하려면 CommonJs 모듈을 참조하세요🎜🎜🎜🎜AMD(비동기식) 모듈 로딩)🎜 🎜🎜🎜 모듈은 비동기적으로 로드되며, 모듈 로딩은 후속 명령문의 실행에 영향을 주지 않습니다. 모듈에 의존하는 모든 문은 콜백 함수에 정의되어 있습니다. 콜백 함수는 로딩이 완료될 때까지 실행되지 않습니다. 🎜🎜🎜🎜사용 예: 🎜🎜🎜// AMD define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... }); // CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... });🎜🎜🎜모듈 로드
require([module], callback);
첫 번째 매개변수 [module]은 배열이고, 내부 멤버가 로드됩니다. 모듈; 두 번째 매개변수 콜백은 성공적으로 로드된 후의 콜백 함수입니다. 🎜🎜🎜🎜 장점: 🎜🎜🎜🎜🎜 브라우저 환경에서 모듈의 비동기 로딩에 적합 🎜🎜🎜🎜 여러 모듈을 병렬로 로드할 수 있음 🎜🎜🎜🎜🎜 단점: 개발 비용 증가, 코드 판독 It 작성이 더 어렵고, 모듈 정의 방식의 의미가 매끄럽지 않습니다🎜🎜🎜🎜 일반적인 모듈식 사고방식을 따르지 않으며 절충된 구현입니다🎜🎜🎜🎜🎜AMD 사양 대표 >require.js 🎜🎜🎜🎜RequireJS의 모듈에 대한 태도는 실행 전입니다. RequireJS는 구현된 AMD 사양이므로 모든 종속 모듈이 먼저 실행됩니다. 즉, RequireJS는 종속 모듈을 미리 실행하며 이는 RequireJS 실행 프로세스를 진행하는 것과 같습니다. 🎜🎜🎜🎜🎜🎜require 함수 종속 모듈을 확인하세요. , 구성 파일에 따라 js 파일의 실제 경로를 가져옵니다🎜🎜🎜🎜js 파일의 실제 경로에 따라 dom에 스크립트 노드를 삽입하고 onload 이벤트를 바인딩하여 모듈이 로드되었다는 알림을 받습니다. . 🎜🎜🎜🎜모든 종속 스크립트가 로드된 후 콜백 함수 호출 🎜🎜🎜🎜CMD 사양(비동기 로딩 모듈) 🎜🎜🎜🎜CMD 사양은 AMD와 매우 유사하고 간단하며 CommonJS 및 Node.js의 모듈 사양을 유지합니다. js CMD 사양에서 호환성이 뛰어나 모듈은 파일입니다. 🎜🎜🎜🎜 정의 모듈은 팩토리 매개변수를 수신하는 전역 함수 정의를 사용합니다. 팩토리는 함수, 객체 또는 문자열일 수 있습니다. 🎜🎜🎜🎜팩토리는 세 개의 매개변수(요구사항, 내보내기, 모듈)가 있는 함수입니다. ): 🎜🎜🎜🎜🎜require는 다른 모듈에서 제공하는 인터페이스를 얻기 위한 유일한 매개변수로 모듈 ID를 받아들이는 메서드입니다. require(id)🎜🎜🎜🎜exports는 모듈 인터페이스를 외부에 제공하는 데 사용되는 개체입니다. 🎜 🎜🎜🎜모듈은 현재 모듈과 관련된 일부 속성과 메서드를 저장하는 개체입니다. 🎜🎜🎜🎜🎜인스턴스: 🎜define(function(require, exports, module) { var a = require('./a'); a.doSomething(); // 依赖就近书写,什么时候用到什么时候引入 var b = require('./b'); b.doSomething(); });
优点:
依赖就近,延迟执行
可以很容易在 Node.js 中运行
缺点:
依赖 SPM 打包,模块的加载逻辑偏重
实现代表库sea.js
:SeaJS对模块的态度是懒执行, SeaJS只会在真正需要使用(依赖)模块时才执行该模块
对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从2.0开始,也改成了可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
AMD推崇依赖前置;CMD推崇依赖就近,只有在用到某个模块的时候再去require。
// AMD define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() ... }); // CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... });
UMD是AMD和CommonJS的糅合
AMD 以浏览器第一原则发展异步加载模块。
CommonJS 模块以服务器第一原则发展,选择同步加载,它的模块无需包装。
UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式;在判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。
(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 () { //module ... });
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
ES6 模块设计思想:尽量的静态化、使得编译时就能确定模块的依赖关系,以及输入和输出的变量(CommonJS和AMD模块,都只能在运行时确定这些东西)。
使用方式:
// 导入 import "/app"; import React from “react”; import { Component } from “react”; // 导出 export function multiply() {...}; export var year = 2018; export default ... ...
优点:
容易进行静态分析
面向未来的 EcmaScript 标准
缺点:
原生浏览器端还没有实现该标准
全新的命令字,新版的 Node.js才支持。
require使用与CommonJs规范,import使用于Es6模块规范;所以两者的区别实质是两种规范的区别;
CommonJS:
对于基本数据类型,属于复制。即会被模块缓存;同时,在另一个模块可以对该模块输出的变量重新赋值。
对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
当使用require命令加载某个模块时,就会运行整个模块的代码。
当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
ES6模块
ES6模块中的值属于【动态只读引用】。
对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。
마지막으로 require/exports는 필수적이고 보편적이며 필요합니다. 실제로 지금까지 작성한 import/export는 실행을 위해 require/exports로 컴파일되기 때문입니다.
관련 권장 사항:
JS 튜토리얼 - 동적 프로그래밍 알고리즘의 배낭 용량 문제
javaScript의 범위 및 클로저에 대한 지식 설명
위 내용은 JS의 프론트엔드 모듈화 상세 분석 및 차이점 비교의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!