异步JavaScript加载器

简介

异步JavaScript加载提供了一种异步加载JavaScript文件的机制。 它有助于提高web应用/浏览器的性能。 除了这一点,它也提供了一种封装许多不同文件中JavaScript文件的方法,这类似于Java中为实现同样目的而使用的诸如import,package和class关键字。 使用传统的同步加载文件的方法,可能会影响有更多的依赖关系(在运行时负载多个JavaScript文件)的应用程序的性能和可用性。

为此,有多个库可以使用。 在定义模块时,这些库并未遵循异步模块定义(AMD)规范。 让我们来讨论一下这些提高异步加载性能的常用库。

同步与异步

HTML页面中,加载JavaScript模块的传统方法是使用<script>元素,加载css文件时,使用<link>元素。 这种处理方式会强制浏览器在不知道它们以来关系的情况下顺序(假定所有的文件已经按照顺序放置)的执行它们。 如果这些文件之间不存在依赖关系,那么按照顺序执行它们是没有问题的。 同样的,它们也可以并行地执行。 这里谈到异步加载的一部分,可能的话,异步加载器都会并行加载JavaScript文件,从而提高效率。 所以,当减少了页面加载多个文件的时间时,便增强了性能。

AMD(异步模块定义)

AMD - 异步模块定义,开发人员编写JavaScript模块时经常使用该标准,按照该标准写出来的模块可以被任何的AMD-非兼容(AMD-complaint)加载器加载。 常用的AMD API包括require(), define(), exports 和 module. require() 函数在执行一组代码之前,加载一系列从属模块/资源。 该代码被放置在一个回调函数中,只有在所有的依赖被加载之后,该回调函数才会以一个单独线程的方式执行。 define() 函数用于和加载器之间交互脚本已加载的模块列表。

Curl.js

Curl.js是一款小巧快速的AMD-非兼容异步加载器。 大多数异步加载器不能在本地文件系统加载,也就是说,你不能按照“file:”协议使用它们,相反,你应该从Web服务器使用他们。 在同样的思路,你必须“http:"或者"https:"协议从Web服务器上加载一个页面来使用curl。

定义模块

define(['dp1', 'dp2', 'dp3' /* etc */], factory);
define(['dp1', 'dp2', 'dp3' /* etc */], module);
define(module);
define(name, ['dp1', 'dp2', 'dp3' /* etc */], factory);
define(name, ['dp1', 'dp2', 'dp3' /* etc */], module);
define(name, module);
  • [‘dp1’, ‘dp2’, ..]: 模块名。 依赖关系可能会被命名为“require”,“exports”或“module。
  • Factory: 定义模块。 以来关系可以作为参数传递给factory。
  • Module: 一个JavaScript对象,函数,构造函数,或原始
  • ame: 用于命名模块的字符串(不常用/推荐)。

一个典型的AMD封装的CommonJS格式的模块定义。 当定义factory函数,其参数没有依赖关系列表时,便假定了这种格式。 参数“exports”和“module”是可选的。

define(function (require, exports, module) {
    var dep1 = require('app/foo');
    exports.foo2 = function () { return foo() + 2; };
});

另一种使用”pseudo-modules“定义模块的方法

define(['require', 'exports', 'module'], function (require, exports, module) {
    var dep1 = require('app/foo');
    exports.foo2 = function () { return foo() + 2; };
});

Script.js

script.js是一个异步的JavaScript加载器,该加载器具有令人惊讶的,可标记的,轻便的足迹。 像其他的JavaScript加载器,它从任何URL按需加载脚本,而不会阻塞加载其他资源。 传统的加载JavaScript文件的方法

<script src="jquery.js"></script>
<script src="some-jquery-plugin.js"></script>
<script src="script-that-uses-plugin.js"></script>

使用script.js

//同时加载jQuery和plugin,并给它一个名字“bundle”

$script(['jquery.js', 'some-jquery-plugin.js'], 'bundle')
$script('script-that-uses-plugin.js')
// in some-jquery-plugin.js
$script.ready('bundle', function() {
  // both jquery & the current plugin are ready
  // plugin code...
})
// in script-that-uses-plugin.js 
$script.ready('bundle', function() {
  // use your plugin
})

使用script.js的其他方式

$script(['jquery.js', 'some-jquery-plugin.js'], function() {
  // both jquery & the current plugin are ready
})

当工作在较大的路径时,建议定义一个路径变量作为基础。 您可以使用如下方法实现

$script.path('/js/modules/')
$script(['dom', 'event'], function () {
  // use dom & event
})

$script.get('http://somedomain.com/base.js', function () {
})

Require.js

Require.js是另一种流行的JavaScript文件和模块加载器。 它可以在jQuery,Rhino和Node等JavaScript环境中使用。 它鼓励使用模块lds,而不是脚本标记来模块化代码。 Require.js采用了特殊的属性data-main来启动脚本加载。

// This sets the baseUrl to the "scripts" directory, and
    // loads a script that will have a module ID of 'main'
<script data-main="scripts/main.js" src="scripts/require.js"></script>

在一般情况下,为模块ID设置路径时,建议使用baseURLs +路径配置(path config)。 读取模块时,Require.js会自动添加.js扩展名,所以我们不需要手动添加.js扩展名。

requirejs.config({
    //By default load any module IDs from js/lib
    baseUrl: 'js/lib',
    //except, if the module ID starts with "app",
    //load it from the js/app directory. paths
    //config is relative to the baseUrl, and
    //never includes a ".js" extension since
    //the paths config could be for a directory.
    paths: {
        app: '../app'
    }
});

// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function   ($,        canvas,   sub) {
    //jQuery, canvas and the app/sub module are all
    //loaded and can be used here now.
});

模块和函数

用一对简单的名称/值,定义一个无依赖关系的模块。

define({
  color: "black",
  size: "unisize"
});

定义一个有依赖关系的函数。

//module in the same directory as current file
define(["./cart", "./list "], function(cart, inventory) {
  //return an object to define the current module.
  return {
    color: "cyan",
    size: "medium",
    addToCart: function() {
      list.decrement(this);
      cart.add(this);
       }
     }
   }
);

定义一个带有简化CommonJS封装器的模块

define(function(require, exports, module) {
  var a = require('a'),
  b = require('b');
  //Return the module value
  return function () {};
}
);

定义一个带有名称的模块

// module name "foo/title"
  define("foo/title",
    ["my/cart", "my/list"],
      function(cart, inventory) {
        //Definition of foo/title object.
       }
);

参考: