Tôi nhớ khi tôi bắt đầu học cách viết code, tôi thấy một số tệp js sử dụng require() để nhập các mô đun và các tệp khác thì lại sử dụng import để nhập. Điều này luôn làm tôi thấy khó hiểu vì không biết sự khác biệt giữa chúng là gì hoặc tại sao lại có sự không nhất quán giữa các tệp như vậy. Sau thời gian học hỏi và nghiên cứu thì cuối cùng tôi cũng đã khám phá ra được nhiều điều mà tôi sẽ chia sẻ với các bạn ngay sau đây.
CommonJS là gì?
CommonJS là một tập hợp các tiêu chuẩn được sử dụng để triển khai các mô đun trong JavaScript phía máy chủ, chủ yếu là môi trường Node.js. Trong hệ thống này, các mô đun được tải đồng bộ, nghĩa là việc thực thi tập lệnh bị chặn cho đến khi mô đun được tải xong hoàn toàn. Điều này tạo nên một cách tiếp cận đơn giản, nhưng nhược điểm là hiệu suất sẽ bị ảnh hưởng nếu bạn đang cố gắng tải một loạt các mô đun khác nhau vì chúng phải tải lần lượt trước khi bất kỳ thứ gì khác có thể chạy.
Khi sử dụng CommonJS, bạn sẽ sử dụng module.exports để xuất chức năng và sử dụng require() để nhập chức năng đó.
Sau đây là ví dụ về cách mà chúng hoạt động sẽ trông như thế nào.
// In file multiple.js module.exports = function multiply(x, y) { return x * y;
};
// In file main.js const multiply = require(‘./multiply.js’); console.log(multiply(5, 4)); // Output: 20
ECMAScript (ES6) là gì?
ES6, còn được gọi là ECMAScript, là phiên bản JavaScript mới hơn được phát hành vào năm 2015. Bản phát hành này đi kèm khả năng nhập các mô đun không đồng bộ bằng cách sử dụng các câu lệnh import và export. Điều này có nghĩa là tập lệnh bạn đang chạy có thể tiếp tục thực thi trong khi mô đun đang được tải vào nên không có tình trạng tắc nghẽn. Điều này có nghĩa là bạn chỉ tải JavaScript từ một mô đun mà bạn đang sử dụng và các đoạn mã không được sử dụng sẽ không được tải vào trình duyệt. Tất cả điều này đều khả thi vì ES6 hỗ trợ cả nhập tĩnh và nhập động.
Đây là ví dụ tương tự như ví dụ trước đó nhưng lần này chúng ta sử dụng cả import và export.
// In file multiply.js export const multiply = (x, y) => x * y;
// In file main.js import { multiply } from ‘./multiply.js’; console.log(multiply(5, 4)); // Output: 20
Vậy thì sự khác biệt chính giữa require và import ở đây là gì?
require() là một phần của hệ thống mô đun CommonJS, trong khi import lại là một phần của hệ thống mô đun ES6. Bạn sẽ thấy require() được sử dụng trong môi trường Node.js để phát triển phía máy chủ, chủ yếu trên các dự án cũ chưa áp dụng ES6. Trong khi đó bạn sẽ thấy import thì lại được sử dụng trong cả phát triển phía máy chủ và giao diện người dùng, đặc biệt là các dự án mới hơn và với bất kỳ framework giao diện người dùng nào như React hoặc Vue.
Thế thì tại sao import lại ưu việt hơn so với require?
Như tôi đã đề cập trước đó, import là hàm không đồng bộ, có thể dẫn đến hiệu suất tốt hơn, đặc biệt là trong các ứng dụng lớn. Ngoài ra, vì import có thể được phân tích tĩnh, các công cụ như linter và bundler có thể tối ưu hóa các đoạn code hiệu quả hơn và triển khai tree shake dẫn đến kích thước bundle nhỏ hơn và thời gian tải nhanh hơn. Cú pháp cũng dễ đọc hơn so với require(), nhờ đó giúp trải nghiệm của lập trình viên tốt hơn, thuận lợi cho công việc về sau.
Vậy khi nào nên dùng import, khi nào dùng require?
Bạn sử dụng require() khi:
- Bạn đang làm việc trên một dự án Node.js cũ được bắt đầu trước khi ES6 ra mắt và chưa được cập nhật.
- Bạn cần tải các mô đun động khi khởi chạy, chẳng hạn như trong tệp cấu hình hoặc nếu bạn cần tải các mô đun có điều kiện.
Còn với các trường hợp còn lại thì tôi khuyên các bạn nên sử dụng import vì sự tiện lợi của nó.
Tóm lại
Nhìn chung, nên sử dụng import bất cứ khi nào có thể, vì nó mang lại nhiều lợi ích hơn và là hệ thống mô đun đời mới hơn, được áp dụng rộng rãi hơn. Tuy nhiên, có thể có những trường hợp require() vẫn là lựa chọn tốt hơn, tùy thuộc vào yêu cầu cụ thể của bạn và môi trường bạn đang làm việc. Tất cả do bạn lựa chọn để phù hợp với mục đích sử dụng và làm việc mà thôi. Cảm ơn các bạn đã theo dõi bài viết này.