1. 语法对比

入口文件引入

requirejs 的引入和入口文件的引入是同一个 script 标签

  1. //在引入 requirejs 的 script 标签的 data-main 属性引入入口文件
  2. <script data-main="src/main.js" src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.min.js"></script>

systemjs 的引入和入口文件的引入是两个单独的 script 标签

  1. //引入 systemjs
  2. <script src="https://cdn.bootcdn.net/ajax/libs/systemjs/6.13.0/system.min.js"></script>
  3. //script 标签指明 type,加载入口文件
  4. <script type="systemjs-module" src="/src/main.js"></script>

模块定义方式

requirejs 使用 define() 方法定义模块,原生支持具名模块定义。

  1. define(['./b.js'], function(b) {
  2. return function() {
  3. console.log('我是 a.js')
  4. b.sayHi()
  5. }
  6. })

systemjs 使用 System.register() 方法定义模块,可通过插件 named-register.js 实现具名模块定义。

  1. System.register(['/src/b.js'], (exports) => {
  2. let b;
  3. return {
  4. setters: [(module) => {
  5. b = module
  6. }],
  7. execute() {
  8. exports({
  9. default: () => {
  10. console.log('我是 a.js')
  11. b.sayHi()
  12. }
  13. })
  14. }
  15. }
  16. })

PS:
具名模块定义在节省文件请求数量,进行多个模块合并在一个文件里的时候很有用。如果不进行模块合并,其实可以直接使用匿名模块,匿名模块的模块名字 id 是默认以其路径为唯一 id。
截屏2022-12-21 下午2.47.35.png
截屏2022-12-21 下午5.18.04.png

模块路径映射方式

  1. require.config({
  2. baseUrl: 'lib',
  3. paths: {
  4. 'compute': 'compute/main'
  5. }
  6. });
  1. <script type="systemjs-importmap">
  2. {
  3. "imports": {
  4. "myquery": "/deps/myquery.js"
  5. }
  6. }
  7. </script>
  8. // Alternatively:
  9. <script type="systemjs-importmap" src="path/to/map.json" crossorigin="anonymous"></script>

模块加载方式(动态导入)

  1. require(['src/a.js', 'myquery'], function(a, myquery) {
  2. console.log('I am main')
  3. a()
  4. console.log(myquery)
  5. })
  1. System.import()

加载其他模块定义方式的模块

requirejs 使用 shim

  1. require.config({
  2. shim: { // 支持iife全局模式的模块
  3. 'backbone': {
  4. //These script dependencies should be loaded before loading
  5. //backbone.js
  6. deps: ['underscore', 'jquery'],
  7. //Once loaded, use the global 'Backbone' as the
  8. //module value.
  9. exports: 'Backbone'
  10. },
  11. 'underscore': {
  12. exports: '_'
  13. },
  14. },
  15. packages: {} // 支持 commonjs 模式的模块
  16. })

systemjs 使用 pluggable extras加载其他模式的模块
截屏2022-12-22 下午2.27.46.png

循环依赖

requirejs 支持循环依赖

  1. //"a" needs "b" and "b" needs "a"
  2. //Inside b.js:
  3. define(["require", "a"],
  4. function(require, a) {
  5. //"a" in this case will be null if "a" also asked for "b",
  6. //a circular dependency.
  7. return function(title) {
  8. return require("a").doSomething();
  9. }
  10. }
  11. );
  12. // requirejs 中的循环依赖用 require 改写

systemjs 支持循环依赖
截屏2022-12-22 下午2.28.47.png

PS: 循环依赖本身是一种代码设计问题,代码编写过程中应该避免循环依赖的出现,但有时候循环依赖也是必须的,无法避免的。两种工具都有对循环依赖的处理。

live bindings

systemjs 支持实时绑定

2. script loading

requirejs

requirejs 使用 head.appendChild(script)的方式进行模块脚本加载。

systemjs

systemjs 使用 head.appendChild(script)的方式进行模块脚本加载,同时在加载完成后又 head.removeChild了脚本模块。

3. 浏览器支持

requirejs

截屏2022-12-21 下午2.00.04.png

systemjs

充分支持到 IE 11,若要支持 IE11 之前版本的浏览器,需要引入 polyfill ,有 promise / fetch 等等 polyfill。

4. 是否支持 file 协议本地读取文件

requirejs

支持
截屏2022-12-21 下午2.36.13.png

systemjs

支持
截屏2022-12-21 下午2.36.55.png

5. 性能对比

截屏2022-12-23 下午5.04.40.png