在JavaScript应用中使用RequireJS来实现延迟加载

2022-10-18,,,,

无论简单还是复杂的web应用,都由一些html、javascript、css文件组成。通常开发者会通过jquery、knockout、underscore等等这样的第三方javascript框架来提高开发速度。由于这些javascript框架都针对特定的用途开发而且已经得到了“验证”,所以直接使用它们就比自己从头实现所需要的功能显得更为合适。然而,伴随着应用的复杂度不断上升,写出干净、低耦合、可维护的代码变得越来越重要。在这篇文章里,我将解释 requirejs框架如何帮助应用开发者写出更加模块化的代码,以及它是如何通过延迟加载javascript文件来提高应用性能的。

开始的部分我们先不用requirejs框架,然后在下一个章节用requirejs来重构它。

下面的这个html页面包含了一个id为“message”的<p>元素。当用户访问这个页面的时候,它将展示订单id和客户姓名信息。

common.js文件包含了两个模块的定义——order和customer。函数showdata和页面的body结合在一起,它通过调用write函数来把要输出的信息放入页面中。作为示例,我在showdata函数里硬编码了id为1,客户姓名为prasad。
 

<!doctype html>
<html>
<head>
<title>javascript nonrequirejs</title>
<script src="common.js" type="text/javascript"></script>
</head>
<body>
<strong>display data without requirejs</strong>
<p id="message" />
<script type="text/javascript">
showdata();
</script>
</body>
</html>
common.js
 
function write(message) {
  document.getelementbyid('message').innerhtml += message + '</br>';
}
 
function showdata() {
  var o = new order(1, "prasad");
  write("order id : " + o.id + " customer name : " + o.customer.name);
}
 
function customer(name) {
  this.name = name;
  return this;
}
 
function order(id, customername) {
  this.id = id;
  this.customer = new customer(customername);
  return this;
}

在浏览器中打开这个页面,你将看到如下的信息。

虽然上面的代码能够显示输出,但是它仍有一些问题:

  •     common.js文件包含了所有需要定义的函数(write,showdata),而且模块(order,customer)很难维护和复用。假如你想在其它页面里复用write函数并引用了上面的javascript文件,那么你也导入了这个页面可能不需要的其它函数和模块。
  •     order模块(或者在面向对象中叫做“类”)在初始化过程中创建了一个customer模块的实例。这意味着order模块依赖于customer模块。这些模块间的紧耦合使得将来在优化时很难重构与维护。
  •     每当客户端请求这个页面时,common.js文件就会被载入dom。在上面这个例子中,尽管我们只需要在页面上输出信息,但我们仍把那些不需要的模块(customer,order)载入了内存。载入不必要的应用资源(javascript、css、图片文件等等)会降低应用的性能。
  •     common.js文件里的模块可以被分离到不同的javascript文件里,但是当应用变得越来越复杂时,很难判断javascript文件之间的依赖关系与需要被加载的文件的加载顺序。

requirejs框架处理了javascript文件间的依赖关系,并且根据需要按顺序加载它们。

用requirejs搭建应用

现在让我们看看重构过的代码。下面的html代码引用了require.js文件。data-main属性定义了这个页面的唯一入口点。在下面这个场景中,它告诉了requirejs在启动的时候加载main.js。
 

<!doctype html>
<html>
<head>
<title>javascript requirejs</title>
<script src="require.js" type="text/javascript" data-main="main.js"></script>
</head>
<body>
<strong>display data using requirejs</strong>
<p id="message" />
</body>
</html>

main.js

由于这个文件已经通过data-main属性指定,requirejs将会尽快的加载它。这个文件使用了requirejs框架的函数来确定和定义对于其它javascript文件的依赖关系。在下面的代码片段里,第一个参数表示依赖关系(依赖order.js文件),第二个参数为一个回调函数。requirejs分析所有的依赖关系并载入它们,然后执行这个回调函数。请注意,第一个参数的值(order)必须和文件名一致(order.js)。
 

require(["order"], function (order) {
  var o = new order(1, "prasad");
  write(o.id + o.customer.name);
});

order.js

requirejs框架提供了一个定义和维护javascript文件间依赖关系的简便途径。下面代码中的define函数声明了customer.js必须在处理order回调函数前载入。
 

define(["customer"],
function (customer) {
function order(id, custname) {
this.id = id;
this.customer = new customer(custname);
}
return order;
}
);
customer.js

这个文件不依赖于任何其它javascript文件,所以define函数的第一个参数的值是一个空数组。
 

define([],
function () {
function customer(name) {
this.name = name;
}
return customer;
}
);

好了,现在用你的浏览器打开这个应用,你将会看到如下的输出。要注意的是requirejs只载入了必需的javascript文件。

 总结

在这篇文章里,我们分析了requirejs框架是如何处理javascript文件间的依赖关系并根据需要载入它们的。它能够帮助开发者写出更松耦合、更模块化且更具有可维护性的代码。

《在JavaScript应用中使用RequireJS来实现延迟加载.doc》

下载本文的Word格式文档,以方便收藏与打印。