为什么要网页模块化?

  这篇文章讨论的是为什么Web模块化是很有用的,并介绍了现在可以用来实现Web模块化的一些机制。这里有另一篇文章介绍了RequireJS使用的函数包装格式的设计理念。

  问题§1

  • 网站逐渐转化为Web apps
  • 代码复杂度逐渐提高
  • 组装变的困难
  • 开发者想要分离的JS文件/模块
  • 部署时可以把代码优化成几个HTTP请求

  解决方案§2

  前端开发者需要这样的解决方案:

  • 一些这类的API #include/import/require
  • 有能力加载嵌套的依赖
  • 对开发者来说易于使用,并且有优化工具在后面支持,有助于部署

  脚本载入API § 3

  首先梳理出脚本载入API。这里有几个选择:

  • Dojo: dojo.require("some.module")
  • LABjs: $LAB.script("some/module.js")
  • CommonJS: require("some/module")

  所有的都映射到载入 some/path/some/module.js。理想情况下,我们可以选择CommonJS的语法,因为它很可能会变得更加常见,而且我们想要重用代码。

  当前我们也希望一些语法能够载入已存在的纯文本JavaScript文件,因此开发者不用重写所有的JavaScript来从脚本载入中获益。

  但是,我们需要一些能在浏览器中更好的工作的事物。CommonJS 的require()是一个同步调用,它期望能够立即返回那个模块。不过这在浏览器中工作的不是很好。

  异步与同步§ 4

  下面这个例子说明了浏览器的基本问题。假设我们有一个Employee对象,我们想要一个派生自Employee对象的Manager对象。获取该例子,我们可能会用我们的脚步载入API来这样编码:


1

2

3

var Employee = require("types/Employee");function Manager () {

    this.reports = [];

}//Error if require call is asyncManager.prototype = new Employee();

  如上面注释中所示,如果require()是异步的,这段代码不会工作。但是,在浏览器中同步载入脚步将会抹杀性能。那么,怎么办?

  脚本载入:XHR§ 5

  使用XMLHttpRequest(XHR)载入脚本是很有吸引力的。如果使用XHR,我们就可以触摸上面的文本,也就是可以通过正则表达式来查找require()调用,以确保我们载入了这些脚本,然后再用eval()或script元素将文本内容传给使用XHR载入的脚本。

  • 使用eval()来评估模块不太好:
  • 开发者已经被告知eval()不好用。
  • 有些环境不支持eval()。
  • 难以调试。Firebug和WebKit的检查器有一个//@ sourceURL= 约定,用来给被评估的文本命名,不过这个特性不是所有的浏览器都支持。
  • 不同的浏览器评估上下文环境是不同的。IE中的execScript或许可以做到,但是同时也意味着更多的移动部件。

  使用带文本内容的script标签来设置为文件文本也不太好:

  • 调试的时候,你得到的错误行号和源文件对不上号。

  XHR 在跨域请求的时候还有问题。一些浏览器现在有跨域XHR的支持,但并不是全部。并且 IE 决定创建一个不同的API对象:XDomainRequest来实现跨域请求。出现了更多的需要改动的地方,更容易出错。特别是,你需要确定不发送任何不标准的HTTPheader或者还需要另外一个"预检"的请求来保证这次跨域的请求是被允许的。

  Dojo 通过eval()使用基于XHR的loader,但是,虽然它能用,但是一直是困扰开发者的源头。Dojo 有一个 xdomain loader但是它需要通过使用一个函数wrapper来修改require的模块,所以script src=""标签可以用来加载模块了。还有很多边界情况和变化的地方来给程序员增加困难。

  如果我们创建一个新的脚本加载器,我们可以做的更好。

  脚本载入:Web Workers § 6

  web worker可能是另一个加载脚本的方法,但是:

  • 它的跨平台性不好
  • 它是一个消息传递API,并且该脚本可能要与DOM交互,它只是使用worker获取脚本的文本,然后将文本回传给主窗口,再用eval/script来执行脚本。这种方法带有上面提到的XHR的全部问题。

  脚本载入:document.write()§ 7

  document.write()可以用来载入脚本,它可以从其他的域载入脚本并且映射了浏览器通常是如何使用脚本的,因此它可以用来进行简单的调试。

  但是,在异步VS同步的例子中,我们不能直接执行脚本。理想情况下,在执行脚本前我们能够通过require()知道相关依赖项,并且确保这些依赖项被首先载入。但是我们不能在脚本执行前访问它。

  而且,document.write()在页面载入后就不工作了。对于你的网站,一个好的方法是在用户需要进行下一步操作时来载入脚本。

  最后,通过document.write()载入脚本或阻塞页面的渲染。要让你的网站有最佳表现,这个方法是不可取的。

  脚本载入:head.appendChild(script)§ 8

  我们可以在需要时创建脚本并将它们添加到头部:


1

2

3

4

5

var head = document.getElementsByTagName(‘head‘)[0],

    script = document.createElement(‘script‘);

script.src = url;

head.appendChild(script);

  上面的脚本片段多了一点东西,不过那正是基本的思想。这种方法比document.write要好,因为它不会阻塞页面的渲染并且在页面载入后仍能工作。

  但是,它仍然有同步VS异步例子的问题:理想情况下,在执行脚本前我们能够通过require()知道相关依赖项,并且确保这些依赖项被首先载入。

  函数封装 § 9

  在执行我们的脚本前,我们需要知道相关依赖项并确保已经将其载入。做这件事的最好方法是通过函数封装来构造我们的模块载入API。像这样:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

define(    //The name of this module

    "types/Manager",    //The array of dependencies

    ["types/Employee"],    //The function to execute when all dependencies have loaded. The

    //arguments to this function are the array of dependencies mentioned

    //above.

    function (Employee) {

        function Manager () {

            this.reports = [];

        }        //This will now work

        Manager.prototype = new Employee();        //return the Manager constructor function so it can be used by

        //other modules.

        return Manager;

    }

);

  这是ReguireJS的句法。如果你想载入没有定义成模块的纯文本的JavaScript的话,有一种简单的句法:


1

2

3

require(["some/script.js"], function() {

    //This function is called after some/script.js has loaded.

});

  选择这种句法是因为,它足够简洁并且允许载入者使用head.appendChild(script)载入类型。

  出于在浏览器中良好工作的需要,它有不同于普通的CommonJS句法。有建议说普通的CommonJS句法可以使用head.appendChild(script)的载入类型,如果服务器进程有封装的函数可以将模块转换成传输格式的话。

  我相信不强制使用一个运行时服务器进程来转换代码是很重要的事:

  • 一是调试变的很怪异,因为服务器在注入封装函数时会导致源文件的行号关闭。
  • 二是需要做更多的工作。前端开发应该尽可能的使用静态文件。

  关于设计的力量和功能封装格式的使用案例的更多细节,被叫做异步模块定义(Asynchronous Module Definition (AMD)),请前往为什么是AMD?

  原文地址:http://requirejs.org/docs/why.html

时间: 2025-02-01 19:57:12

为什么要网页模块化?的相关文章

Gulp-静态网页模块化

前言: 在做纯静态页面开发的过程中,难免会遇到一些的尴尬问题.比如:整套代码有50个页面,其中有40个页面顶部和底部模块相同.那么同样的两段代码我们复制了40遍(最难受的方法).然后,这个问题就这样解决了.再然后,产品经理看了几遍后突然说顶部的某块需要改改设计...突然感觉好尴尬~~(心里是万马奔腾~),然后呢?然后就期待下一次的万马奔腾!!! 虽然类似问题的解决方案很多,但是纯前端,不用各种框架的情况下,一种比iframe更靠谱的解决方案莫过于用像gulp这样的构建工具来完成.虽然在体验上也许

2017,你好

2017,你好 2017,日历翻到了本命年,车子开到了十万公里,接触PC和了解IT业已经足足二十个年头. 关于IT的话题,2017年的确是到了值得暂停下来好好回顾和小结一番的时候了.我20年前的今天1997年1月9日通过专业技术人员知识普及读本才开始接触到计算机知识,1997年7月份第一次接触PC机,同年9月份参加了计算机中级培训班系统学习计算机知识,1997年10月份开始在386计算机DOS6.22版本操作系统上用FoxBase学习数据库编程,出于对PC智能化酷爱,对数据库的热爱,一干就干了二

前端学习笔记 - Css初级篇

有话先说:我是一只菜鸟,一只都是,从前是现在也是. CSS中的会计元素与行内元素 块级元素特性:占据一整行,总是重起一行并且后面的元素也必须另起一行显示.内联元素特性:和其他内联元素显示在同一行. 可以知道的是,行内元素和块级元素之间是能够相互转换的.趋于对网页模块化的搭建,后期行内转换为块级的例子会很多很多. html中的块级元素列举如下: div(文档分区),article(文章内容), aside(伴随内容), audio(音频播放), blockquote(块引用), canvas(绘制

OSChina 技术周刊第十期,每周技术抢先看!

每周技术抢先看,总有你想要的! 移动开发 [软件]Android 表单验证框架 - AValidations [软件][email protected] 的 iPhone 客户端 [软件][email protected] 的 Android 客户端 [博客]使用gradle构建android项目(续) 前端开发 [翻译]AngularJS ui-router (嵌套路由) [软件]ChartSQL -- 用 SQL 语句来生成图形图表 [软件]Flow -- Facebook 的 JavaSc

methanol 模块化的可定制的网页爬虫软件,主要的优点是速度快。

methanol模块化的可定制的网页爬虫软件,主要的优点是速度快. 下载:http://sourceforge.net/projects/methabot/?source=typ_redirect README 安装SpiderMonkey https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Build_Documentation

网页高效重构思想

说起模块化,首先想到的是编程中的模块设计,以功能块为单位进行程序设计,最后通过模块的选择和组合构成最终产品.把这种思想运用到页面构建中,也已经不是什么新鲜事.相信很大一部分页面构建工程师都经历了这样几个阶段:第一阶段是在一个css文件中把多个页面按自己的习惯顺序从上往下编写样式,基本不考虑有无公用样式,以完成设计呈现为首要目的:第二阶段是提取不同页面中的通用样式,如公用颜色.图标.按钮等,实现一些基本元素的复用:第三阶段是提取公用功能模块,如导航.版权信息等,实现部分公用模块的复用. 刚才描述的

Javascript模块化编程(二):AMD规范

作者: 阮一峰 日期: 2012年10月30日 这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. (接上文) 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块. 但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!考虑到Javascript模块现在还没有官方规范,这一点就更重要了. 目前,通行的Javascript模块规范共有两种

前端模块化

前端模块化 前端模块化 在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可:如今CPU.浏览器性能得到了极大的提升,很多页面逻辑迁移到了客 户端(表单验证等),随着web2.0时代的到来,Ajax技术得到广泛应用,jQuery等前端库层出不穷,前端代码日益膨胀 这时候JavaScript作为嵌入式的脚本语言的定位动摇了,JavaScript却没有为组织代码提供任何明显帮助,甚至没有类的概念,更不用说模块(module)了,JavaScript极其简单的代码组织规范不足以驾

JS模块化工具requirejs教程(一):初识requirejs

随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求. RequireJS是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一.最新版本的RequireJS压缩后只有14K,堪称非常轻量.它还同时可以和其他的框架协同工作,使用RequireJS必将使您的前端代码质量得以提升. requirejs能带来什么好处 官方对requ