>웹 프론트엔드 >프런트엔드 Q&A >프런트엔드 모듈형 AMD와 CMD의 차이점은 무엇입니까?

프런트엔드 모듈형 AMD와 CMD의 차이점은 무엇입니까?

青灯夜游
青灯夜游원래의
2020-11-18 09:41:252311검색

차이점: AMD와 CMD는 종속 모듈의 실행 타이밍을 다르게 처리합니다. AMD는 사전 종속성을 옹호하며, CMD는 특정 모듈이 사용될 때만 인근 종속성을 옹호합니다. .

프런트엔드 모듈형 AMD와 CMD의 차이점은 무엇입니까?

JavaScript 개발 초기에는 몇 마디만으로 간단한 페이지 상호 작용 로직을 구현하는 것이었지만 이제는 CPU와 브라우저 성능이 크게 향상되었으며 많은 페이지 로직이 클라이언트(폼검증 등), 웹 2.0 시대의 도래와 함께 Ajax 기술이 널리 사용되고 jQuery 등의 프론트엔드 라이브러리도 속속 등장하며 프론트엔드 코드도 점점 확장되고 있습니다

이제 임베디드 스크립팅 언어로서의 JavaScript의 위치가 흔들렸지만 JavaScript는 구성 코드를 제공하지 않습니다. 분명히 도움이 되는 것은 모듈은 물론이고 JavaScript의 매우 간단한 코드 구성 사양도 충분하지 않습니다. 이렇게 큰 규모의 코드를 처리하려면

Module

JavaScript는 이렇게 큰 규모의 코드를 처리할 수 없기 때문에 다른 언어가 대규모 프로그래밍을 처리하는 방법을 통해 배울 수 있습니다. Java에는 중요한 개념이 있습니다. 패키지. 논리적으로 관련된 코드는 동일한 패키지로 구성됩니다. 패키지 내에서는 상대적으로 독립적인 왕국이므로 이름 충돌에 대해 걱정할 필요가 없습니다. 해당 패키지를 가져오기하세요package,逻辑上相关的代码组织到同一个包内,包内是一个相对独立的王国,不用担心命名冲突什么的,那么外部如果使用呢?直接import对应的package即可

import java.util.ArrayList;

遗憾的是JavaScript在设计时定位原因,没有提供类似的功能,开发者需要模拟出类似的功能,来隔离、组织复杂的JavaScript代码,我们称为模块化。

一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,各行其是就都乱套了

规范形成的过程是痛苦的,前端的先驱在刀耕火种、茹毛饮血的阶段开始,发展到现在初具规模,简单了解一下这段不凡的历程

函数封装

我们在讲函数的时候提到,函数一个功能就是实现特定逻辑的一组语句打包,而且JavaScript的作用域就是基于函数的,所以把函数作为模块化的第一步是很自然的事情,在一个文件里面编写几个相关函数就是最开始的模块了

function fn1(){
    statement
}

function fn2(){
    statement
}

这样在需要的以后夹在函数所在文件,调用函数就可以了

这种做法的缺点很明显:污染了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间没什么关系。

对象

为了解决上面问题,对象的写法应运而生,可以把所有的模块成员封装在一个对象中

var myModule = {
    var1: 1,

    var2: 2,

    fn1: function(){

    },

    fn2: function(){

    }
}

这样我们在希望调用模块的时候引用对应文件,然后

myModule.fn2();

这样避免了变量污染,只要保证模块名唯一即可,同时同一模块内的成员也有了关系

看似不错的解决方案,但是也有缺陷,外部可以随意修改内部成员

myModel.var1 = 100;

这样就会产生意外的安全问题

立即执行函数

可以通过立即执行函数,来达到隐藏细节的目的

var myModule = (function(){
    var var1 = 1;
    var var2 = 2;

    function fn1(){

    }

    function fn2(){

    }

    return {
        fn1: fn1,
        fn2: fn2
    };
})();

这样在模块外部无法修改我们没有暴露出来的变量、函数

上述做法就是我们模块化的基础,目前,通行的JavaScript模块规范主要有两种:CommonJSAMD

CommonJS

我们先从CommonJS谈起,因为在网页端没有模块化编程只是页面JavaScript逻辑复杂,但也可以工作下去,在服务器端却一定要有模块,所以虽然JavaScript在web端发展这么多年,第一个流行的模块化规范却由服务器端的JavaScript应用带来,CommonJS规范是由NodeJS发扬光大,这标志着JavaScript模块化编程正式登上舞台。

  1. 定义模块
    根据CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性

  2. 模块输出:
    模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象

  3. 加载模块:
    加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

看个例子

//模块定义 myModel.js

var name = 'Byron';

function printName(){
    console.log(name);
}

function printFullName(firstName){
    console.log(firstName + name);
}

module.exports = {
    printName: printName,
    printFullName: printFullName
}

//加载模块

var nameModule = require('./myModel.js');

nameModule.printName();

不同的实现对require时的路径有不同要求,一般情况可以省略js

// 定义模块 myModule.js
define(['dependency'], function(){
    var name = 'Byron';
    function printName(){
        console.log(name);
    }

    return {
        printName: printName
    };
});

// 加载模块
require(['myModule'], function (my){
  my.printName();
});
안타깝게도 JavaScript는 설계 중 위치 지정으로 인해 유사한 기능을 제공하지 않습니다. 개발자는 복잡한 JavaScript 코드를 분리하고 구성하기 위해 유사한 기능을 시뮬레이션해야 합니다. 이를 모듈성이라고 합니다.

모듈은 특정 기능을 구현하는 파일입니다. 모듈을 사용하면 우리가 원하는 기능에 대해 다른 사람의 코드를 보다 편리하게 사용할 수 있습니다. 모듈 개발은 정해진 기준을 따라야 하는데, 제멋대로 하면 다들 엉망이 됩니다프론트엔드의 선구자들은 화전 단계에서 시작해서, 그 기준을 만드는 과정이 고통스럽습니다. 피를 마시며 이제 개발이 구체화되기 시작했습니다. 이 특별한 여정을 간단히 이해해 봅시다

🎜Function Encapsulation🎜🎜🎜함수에 관해 이야기할 때 함수의 한 가지 함수는 구현하는 일련의 명령문을 패키지하는 것이라고 언급했습니다. 특정 로직이 있고 JavaScript의 범위는 함수를 기반으로 하므로 함수를 모듈화하는 첫 번째 단계는 초기 모듈로 여러 관련 함수를 파일에 작성하는 것이 당연합니다🎜
define(id?, dependencies?, factory);
🎜이런 식으로 필요할 때 클립할 수 있습니다. 함수가 있는 파일에 추가하고 함수를 호출하세요🎜🎜이 접근 방식의 단점은 명백합니다. 오염 전역 변수가 없으면 변수 이름이 다른 모듈과 충돌하지 않는다는 보장이 없으며 모듈 멤버 간의 관계도 없습니다. 🎜🎜🎜Object🎜🎜🎜위 문제를 해결하기 위해 모듈의 모든 멤버를 하나의 객체로 캡슐화할 수 있는 객체 작성 방법이 등장했습니다🎜
require([dependencies], function(){});
🎜이렇게 모듈을 호출하고자 할 때, 그런 다음🎜
define(id?, deps?, factory)
🎜이렇게 변수 오염을 방지하려면 모듈 이름이 고유하고 동일한 모듈의 멤버도 관련되어 있는지 확인하십시오.🎜🎜좋은 해결책인 것처럼 보이지만 외부 멤버에도 결함이 있습니다. 내부 멤버를 임의로 수정할 수 있습니다🎜
function(require, exports, module)
🎜예상치 못한 문제가 발생할 수 있습니다. 보안 문제🎜🎜🎜함수 즉시 실행🎜🎜🎜함수를 즉시 실행하여 세부 사항을 숨길 수 있습니다🎜
require(id)
🎜이렇게 우리가 노출하지 않은 변수와 함수는 공개할 수 없습니다. 모듈 외부에서 수정됨🎜🎜위 접근 방식은 모듈화의 기초입니다. 현재 널리 사용되는 두 가지 주요 JavaScript 모듈 사양이 있습니다: CommonJSAMD🎜🎜🎜CommonJS🎜🎜 🎜웹 페이지에는 모듈이 없기 때문에 CommonJS부터 시작하겠습니다. 페이지의 JavaScript는 복잡한 로직을 가지고 있지만 서버측에는 여전히 모듈이 있어야 합니다. 따라서 JavaScript는 웹에서 개발되었지만 작동합니다. 수년 동안 최초의 인기 있는 모듈화 사양은 서버측 JavaScript 애플리케이션에서 나왔습니다. CommonJS 사양은 NodeJS에 의해 계승되었으며, 이는 JavaScript 모듈식 프로그래밍의 공식 항목이 되었습니다. 🎜
  1. 🎜모듈 정의
    CommonJS 사양에 따르면 단일 파일이 모듈입니다. 각 모듈은 별도의 범위입니다. 즉, 모듈 내에 정의된 변수는 전역 객체의 속성으로 정의되지 않는 한 다른 모듈에서 읽을 수 없습니다🎜
  2. 🎜모듈 출력: 모듈에는 module.exports 객체라는 하나의 내보내기만 있습니다. 모듈이 출력하려는 ​​콘텐츠를 이 객체에 넣어야 합니다🎜
  3. 🎜모듈 로드:
    모듈 로드 파일을 읽고 실행하여 파일 내부에 module.exports 객체를 반환하는 require 메서드를 사용하세요🎜
🎜보세요 예🎜
// 定义模块  myModule.js
define(function(require, exports, module) {
  var $ = require('jquery.js')
  $('p').addClass('active');
});

// 加载模块
seajs.use(['myModule.js'], function(my){

});
🎜구현마다 필요할 때 경로에 대한 요구 사항이 다릅니다. 일반적으로 js 확장자를 생략하거나, 상대 경로를 사용하거나, 절대 경로를 사용하거나, 경로를 생략하고 사용할 수도 있습니다. 모듈 이름을 직접 입력합니다(이 모듈이 시스템에 내장된 모듈인 경우)🎜🎜🎜🎜어색한 브라우저🎜🎜🎜

仔细看上面的代码,会发现require是同步的。模块系统需要同步读取模块文件内容,并编译执行以得到模块接口。

这在服务器端实现很简单,也很自然,然而, 想在浏览器端实现问题却很多。

浏览器端,加载JavaScript最佳、最容易的方式是在document中插入script 标签。但脚本标签天生异步,传统CommonJS模块在浏览器环境中无法正常加载。

解决思路之一是,开发一个服务器端组件,对模块代码作静态分析,将模块与它的依赖列表一起返回给浏览器端。 这很好使,但需要服务器安装额外的组件,并因此要调整一系列底层架构。

另一种解决思路是,用一套标准模板来封装模块定义,但是对于模块应该怎么定义和怎么加载,又产生的分歧:

AMD

AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范

由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出

requireJS主要解决两个问题

  1. 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  2. js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

看一个使用requireJS的例子

// 定义模块 myModule.js
define(['dependency'], function(){
    var name = 'Byron';
    function printName(){
        console.log(name);
    }

    return {
        printName: printName
    };
});

// 加载模块
require(['myModule'], function (my){
  my.printName();
});

语法

requireJS定义了一个函数 define,它是全局变量,用来定义模块

define(id?, dependencies?, factory);
  1. id:可选参数,用来定义模块的标识,如果没有提供该参数,脚本文件名(去掉拓展名)
  2. dependencies:是一个当前模块依赖的模块名称数组
  3. factory:工厂方法,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值

在页面上使用require函数加载模块

require([dependencies], function(){});

require()函数接受两个参数

  1. 第一个参数是一个数组,表示所依赖的模块
  2. 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

CMD

CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同

语法

Sea.js 推崇一个模块一个文件,遵循统一的写法

define

define(id?, deps?, factory)

因为CMD推崇

  1. 一个文件一个模块,所以经常就用文件名作为模块id
  2. CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写

factory有三个参数

function(require, exports, module)

require

require 是 factory 函数的第一个参数

require(id)

require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口

exports

exports 是一个对象,用来向外提供模块接口

module

module 是一个对象,上面存储了与当前模块相关联的一些属性和方法

demo

// 定义模块  myModule.js
define(function(require, exports, module) {
  var $ = require('jquery.js')
  $('p').addClass('active');
});

// 加载模块
seajs.use(['myModule.js'], function(my){

});

AMD与CMD区别

关于这两个的区别网上可以搜出一堆文章,简单总结一下

最明显的区别就是在模块定义时对依赖的处理不同

  • AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块

  • CMD推崇就近依赖,只有在用到某个模块的时候再去require

这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,注意不是加载的时机或者方式不同

많은 사람들이 requireJS는 비동기식 로딩 ​​모듈이고 SeaJS는 동기식 로딩 ​​모듈이라고 말합니다. 실제로 이러한 이해는 정확하지 않습니다. 실제로 로딩 모듈은 모두 비동기식이지만 AMD는 프런트 엔드에 의존하므로 js는 쉽게 알 수 있습니다. 종속 모듈은 즉시 로드되고 CMD는 근처 종속성에 의존하므로 모듈을 사용하여 문자열로 변환하고 어떤 모듈이 종속되어 있는지 알아야 합니다. 이는 많은 사람들이 CMD를 비판하는 지점이기도 합니다. 사실, 모듈을 파싱하는 데 걸리는 시간은 무시할 수 있을 정도로 짧습니다

왜 둘의 차이가 종속 모듈의 실행 시점이 다르다고 할까요? ADM은 비동기식이고 CMD는 동기식이라고 생각하세요(이름 제외...)

두 모듈 모두 비동기식으로 로드되므로 AMD는 모듈을 모두 로드하고 실행한 후 수정된 모듈을 실행합니다. 콜백 함수가 필요하고 메인 로직을 실행하면 네트워크 속도에 따라 종속 모듈의 실행 순서와 쓰기 순서가 반드시 일치하지는 않지만, 어느 것이 먼저 다운로드되는지는 알 수 없습니다. 메인 로직은 모든 ​​의존성 로딩이 완료된 후에 실행되어야 합니다

CMD는 특정 종속 모듈을 로딩한 후에 실행되지 않고 단지 다운로드만 되며, 모든 종속 모듈이 로딩된 후에 메인 로직에 들어가며, 해당 모듈이 실행되는 경우에만 해당 모듈이 실행됩니다. require 문을 만나면 모듈의 실행 순서와 쓰기 순서가 완전히 일관됩니다

이렇게 많은 사람들이 AMD 사용자 경험이 좋다고 말하는 이유는 지연이 없고 종속 모듈이 미리 실행되고 CMD가 있기 때문입니다. 사용자가 필요할 때만 실행되기 때문에 성능이 좋습니다

더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 비디오를 방문하세요! !

위 내용은 프런트엔드 모듈형 AMD와 CMD의 차이점은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.