Mối quan hệ giữa CommonJS, AMD và RequireJS?


840

Tôi vẫn rất bối rối về CommonJS, AMDRequireJS , ngay cả khi đã đọc rất nhiều.

Tôi biết rằng CommonJS (trước đây là ServerJS ) là một nhóm để xác định một số đặc tả JavaScript (tức là các mô-đun) khi ngôn ngữ được sử dụng bên ngoài trình duyệt. Đặc tả mô-đun CommonJS có một số triển khai như Node.js hoặc RingoJS , phải không?

Mối quan hệ giữa CommonJS , Định nghĩa mô-đun không đồng bộ (AMD) và RequireJS là gì?

RequireJS có phải là một triển khai định nghĩa mô-đun CommonJS không? Nếu có, AMD thì sao?


31
Việc đọc requestjs.org/docs/whyamd.html sẽ làm rõ hơn rất nhiều vì nó đề cập đến tất cả chúng. (đăng nó như một bình luận vì tôi không coi đây là một câu trả lời đầy đủ).
mmutilva

5
Tôi có thể hỏi hoặc thêm nhiều hơn; Làm thế nào hoặc ở đâu các báo cáo nhập ES2015 phù hợp với tất cả các báo cáo này; ví dụ: nhập Ember từ 'ember';
testndtv

Ngoài ra còn có một systemjs tải bất kỳ định dạng mô-đun JS được hỗ trợ nào như (CommonJS, UMD, AMD, ES6).
Andy

Câu trả lời:


770

RequireJS thực hiện API AMD (nguồn) .

CommonJS là một cách xác định các mô-đun với sự trợ giúp của một exportsđối tượng, xác định nội dung mô-đun. Nói một cách đơn giản, một triển khai CommonJS có thể hoạt động như thế này:

// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule'); // in the vein of node    
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

Về cơ bản, CommonJS chỉ định rằng bạn cần có một require()hàm để tìm nạp các phụ thuộc, một exportsbiến để xuất nội dung mô-đun và một định danh mô-đun (mô tả vị trí của mô-đun được đề cập liên quan đến mô-đun này) được sử dụng để yêu cầu các phụ thuộc ( nguồn ). CommonJS có nhiều triển khai khác nhau, bao gồm Node.js mà bạn đã đề cập.

CommonJS không được thiết kế đặc biệt dành cho trình duyệt, vì vậy nó không phù hợp lắm với môi trường trình duyệt ( tôi thực sự không có nguồn nào cho việc này - nó chỉ nói như vậy ở mọi nơi, kể cả trang web RequireJS. ) làm với tải không đồng bộ, vv

Mặt khác, RequireJS triển khai AMD, được thiết kế để phù hợp với môi trường trình duyệt ( nguồn ). Rõ ràng, AMD đã bắt đầu như một spinoff của định dạng CommonJS Transport và phát triển thành API định nghĩa mô-đun của riêng mình. Do đó sự tương đồng giữa hai. Tính năng mới trong AMD là define()chức năng cho phép mô-đun khai báo các phụ thuộc của nó trước khi được tải. Ví dụ: định nghĩa có thể là:

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
  return ModuleContents;  
});

Vì vậy, CommonJS và AMD là các API định nghĩa mô-đun JavaScript có các triển khai khác nhau, nhưng cả hai đều có cùng nguồn gốc.

  • AMD phù hợp hơn với trình duyệt, bởi vì nó hỗ trợ tải phụ thuộc mô-đun không đồng bộ.
  • RequireJS là một triển khai của AMD , đồng thời cố gắng giữ tinh thần của CommonJS (chủ yếu trong các định danh mô-đun).

Để làm bạn bối rối hơn nữa, RequireJS, trong khi đang triển khai AMD, cung cấp trình bao bọc CommonJS để các mô-đun CommonJS gần như có thể được nhập trực tiếp để sử dụng với RequireJS.

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

Tôi hy vọng điều này sẽ giúp làm rõ mọi thứ!


7
Hãy xem dự án uRequire.org thu hẹp khoảng cách của 2 định dạng - viết bằng một trong hai (hoặc cả hai), triển khai đến bất kỳ một trong hai hoặc <script> đơn giản
Angelos Pikoulas

51
FYI Browserify sẽ cho phép bạn sử dụng CommonJS trong trình duyệt.
Bỏ trốn

9
@Eruant Nhưng, nó vẫn không có tính chất không đồng bộ như AMD.
Inanc Gumus

8
Lý do tại sao CommonJS không phù hợp với trình duyệt như được đề cập trong tài liệu RequireJS - "CommonJS yêu cầu () là một cuộc gọi đồng bộ, dự kiến ​​sẽ trả lại mô-đun ngay lập tức. Điều này không hoạt động tốt trong trình duyệt" . Thêm thông tin ở đây .
msenni

4
@aaaaaa bạn có thể muốn kích hoạt một số tính năng tùy theo yêu cầu của người dùng; vì vậy bản chất không đồng bộ của AMD có thể có ích.
Inanc Gumus 4/2/2015

199

CommonJS còn hơn thế - đó là một dự án để xác định API và hệ sinh thái chung cho JavaScript. Một phần của CommonJS là đặc tả Module . Node.js và RingoJS là thời gian chạy JavaScript phía máy chủ và vâng, cả hai đều triển khai các mô-đun dựa trên thông số Mô-đun CommonJS.

AMD (Định nghĩa mô-đun không đồng bộ) là một đặc điểm kỹ thuật khác cho các mô-đun. RequireJS có lẽ là triển khai AMD phổ biến nhất. Một điểm khác biệt lớn so với CommonJS là AMD chỉ định rằng các mô-đun được tải không đồng bộ - điều đó có nghĩa là các mô-đun được tải song song, trái ngược với việc chặn thực thi bằng cách chờ tải xong.

AMD thường được sử dụng nhiều hơn trong phát triển JavaScript phía máy khách (trong trình duyệt) do điều này và các Mô-đun CommonJS thường được sử dụng phía máy chủ. Tuy nhiên, bạn có thể sử dụng một trong hai thông số mô-đun trong một trong hai môi trường - ví dụ: RequireJS cung cấp các hướng để chạy trong Node.jsbrowserify là một triển khai Mô-đun CommonJS có thể chạy trong trình duyệt.


20
Tại sao trang chủ CommonJS lại kinh khủng như vậy ... Tôi chỉ đang cố gắng xem thông số chính thức. Nó có lỗi cú pháp, tài liệu không đầy đủ và trang wiki không giải quyết được.
taco

7
Đó không phải là ý nghĩa của việc tải các mô-đun không đồng bộ. Bạn có thể nói về tải động / lười biếng. Với async, bạn đề xuất một tệp để tải và sau đó một thời gian sau nó sẽ gọi lại khi tải xong. Với đồng bộ hóa, bạn đề xuất một tệp để tải và sau đó toàn bộ khối luồng cho đến khi tệp đó tải xong; không có mã nào thực thi cho đến khi tập tin tải. Cái trước có thể mang lại hiệu suất tốt hơn với chi phí không thể đoán trước, trong khi cái sau có thể mang lại kết quả tương tự mọi lúc và do đó dễ dự đoán hơn. Hãy lưu ý những quirks này có thể được giảm thiểu bằng cách sử dụng các tối ưu hóa khác nhau.
perry

Cảm ơn câu trả lời. Bây giờ các mô-đun là chính thức trong JS với ES2015, điều này có nghĩa là chúng được ưu tiên nhiều hơn AMD hoặc JS thông thường?
Akhoy

Điều đó không có nghĩa là chúng được ưa thích. Đó là tất cả tùy thuộc vào nhu cầu của nhà phát triển. Tôi không nghĩ rằng không có tùy chọn nào và sử dụng các mô-đun ES6 là ý tưởng đặc biệt tốt. Tuy nhiên, sử dụng UMD tốt, bạn có thể chống lại vấn đề đó. Tải các gói CommonJS được đồng bộ hóa với AMD là một ý tưởng tốt (tốt nhất) nói chung (để cải thiện lợi ích hiệu suất). Nếu bạn cảm thấy như bạn nên kiểm soát nhiều hơn, rõ ràng. Và bạn nên.
Maciej Sitko

187

Câu trả lời ngắn gọn sẽ là:

CommonJS AMD là các thông số kỹ thuật (hoặc định dạng) về cách các mô-đun và các phụ thuộc của chúng nên được khai báo trong các ứng dụng javascript.

RequireJS là một thư viện trình tải tập lệnh tuân thủ AMD, curljs là một ví dụ khác.

Tuân thủ CommonJS:

Lấy từ cuốn sách của Addy Osmani .

// package/lib is a dependency we require
var lib = require( "package/lib" );

// behavior for our module
function foo(){
    lib.log( "hello world!" );
}

// export (expose) foo to other modules as foobar
exports.foobar = foo;

Tuân thủ AMD:

// package/lib is a dependency we require
define(["package/lib"], function (lib) {

    // behavior for our module
    function foo() {
        lib.log( "hello world!" );
    }

    // export (expose) foo to other modules as foobar
    return {
        foobar: foo
    }
});

Một nơi khác mô-đun có thể được sử dụng với:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

Một số nền tảng:

Trên thực tế, CommonJS không chỉ là một tuyên bố API và chỉ là một phần của nó liên quan đến điều đó. AMD bắt đầu như một đặc điểm kỹ thuật dự thảo cho định dạng mô-đun trong danh sách CommonJS, nhưng không đạt được sự đồng thuận hoàn toàn và sự phát triển hơn nữa của định dạng được chuyển sang nhóm amdjs . Các tranh luận xung quanh định dạng nào là trạng thái tốt hơn mà CommonJS cố gắng giải quyết một loạt các mối quan tâm rộng hơn và nó phù hợp hơn cho sự phát triển phía máy chủ vì tính chất đồng bộ của nó và AMD phù hợp hơn với sự phát triển của phía máy khách (tính chất trình duyệt) có tính chất không đồng bộ và thực tế là nó có nguồn gốc từ việc triển khai mô-đun của Dojo.

Nguồn:


1
Xem mã hơn là mô tả giúp! :) AMD compliantthực sự là RequireJS, phải không?
Asim KT

Tôi đang thiếu một cái gì đó, hoặc có một cái gì đó sai lầm? Bạn định nghĩa "gói / lib" nhưng sau đó yêu cầu "gói / myModule".
RullDawg

Tôi luôn thích đọc một chút về lịch sử tại sao nó lại như vậy! Cảm ơn đã cung cấp nền tảng đó!
Andru

@RullDawg Không, gói / lib lib không được xác định ở đây, đây là phần phụ thuộc của bên thứ 3 được sử dụng ở đây.
Robert Siemer

28

Trích dẫn

AMD :

  • Một cách tiếp cận trình duyệt đầu tiên
  • Lựa chọn hành vi không đồng bộ và tương thích ngược đơn giản hóa
  • Nó không có bất kỳ khái niệm nào về Tệp I / O.
  • Nó hỗ trợ các đối tượng, hàm, hàm tạo, chuỗi, JSON và nhiều loại mô-đun khác.

CommonJS :

  • Cách tiếp cận đầu tiên của máy chủ
  • Giả sử hành vi đồng bộ
  • Bao gồm một loạt các mối quan tâm rộng hơn như I / O, Hệ thống tệp, Lời hứa và nhiều hơn nữa.
  • Hỗ trợ các mô-đun chưa được mở, nó có thể cảm thấy gần hơn một chút với các thông số kỹ thuật ES.next/Harmony , giải phóng bạn khỏi trình bao bọc xác định () AMDthực thi.
  • Chỉ hỗ trợ các đối tượng như các mô-đun.

17

Việc tổ chức chương trình JavaScript thành mô-đun thành nhiều tệp và gọi child-modulestừ main js module.

Vấn đề là JavaScript không cung cấp điều này. Ngay cả ngày nay trong các phiên bản trình duyệt mới nhất của Chrome và FF.

Nhưng, có từ khóa nào trong JavaScript để gọi một mô-đun JavaScript khác không?

Câu hỏi này có thể là một sự sụp đổ hoàn toàn của thế giới đối với nhiều người vì câu trả lời là Không .


Trong ES5 (phát hành năm 2009) JavaScript không có từ khóa như nhập , bao gồm hoặc yêu cầu .

ES6 lưu ngày (phát hành năm 2015) đề xuất từ khóa nhập ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), nhưng không có trình duyệt nào thực hiện điều này.

Nếu bạn chỉ sử dụng Babel 6.18.0 và dịch mã với tùy chọn ES2015

import myDefault from "my-module";

bạn sẽ nhận được requiremột lần nữa.

"use strict";
var _myModule = require("my-module");
var _myModule2 = _interopRequireDefault(_myModule);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

Điều này là do requirecó nghĩa là mô-đun sẽ được tải từ Node.js. Node.js sẽ xử lý mọi thứ, từ đọc tệp cấp hệ thống đến gói chức năng vào mô-đun.

Bởi vì trong các hàm JavaScript là các hàm bao duy nhất để biểu diễn các mô-đun.

Tôi rất bối rối về CommonJS và AMD?

Cả CommonJS và AMD chỉ là hai kỹ thuật khác nhau để khắc phục "lỗi" JavaScript để tải các mô-đun thông minh.


3
Nên cập nhật câu trả lời của bạn vì bây giờ tất cả các trình duyệt hiện đại đều hỗ trợ import
vsync

@vsync, vâng, vui lòng chỉnh sửa câu trả lời của tôi, vì tôi đã không theo dõi phân khúc này một thời gian.
prosti
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.