为什么要网页模块化?
这篇文章讨论的是为什么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
转载于:https://www.cnblogs.com/gongcheng9990/p/4107843.html
为什么要网页模块化?相关推荐
- gulp html 模块化,使用Gulp如何实现静态网页模块化具体怎么做?
众所周知Gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务.下面这篇文章主要给大家介绍了关于Gulp实现静态网页模块化的相关资料,文中通过示例代码介绍的非常详细,需 ...
- Gulp-静态网页模块化
前言: 在做纯静态页面开发的过程中,难免会遇到一些的尴尬问题.比如:整套代码有50个页面,其中有40个页面顶部和底部模块相同.那么同样的两段代码我们复制了40遍(最难受的方法).然后,这个问题就这样解 ...
- gulp临时服务器显示html页面,Gulp实现静态网页模块化的方法详解
前言 在做纯静态页面开发的过程中,难免会遇到一些的尴尬问题.比如:整套代码有50个页面,其中有40个页面顶部和底部模块相同.那么同样的两段代码我们复制了40遍(最难受的方法).然后,这个问题就这样解决 ...
- 前端html页面模块,页面模块化实现的条件和基本实现思路 – WEB前端开发
页面模块化实现的很大的受制于页面的结构和表现:一个统一的页面结构和表现能很好的实现页面的模块话. 比如一个"网友评论"模块这个会在很多地方使用到,比如日志,照片,等等,如果这个&q ...
- html img调用js,html调用js变量 如何在html中输出js文件中的变量
html页面代码中怎么调用js变量?html页面代码中怎么调用js变量,例如 在html代码中插入js代码: a=取浏览你把index1.js 中的onReady 去掉,把index1.js改成 fu ...
- dw中css目标规则命名,CSS名规则.doc
CSS名规则 CSS-命名总结 热度 2已有 26 次阅读 2010-8-13 23:42 |个人分类:资料库|关键词:CSS 命名 HYPERLINK "" CSS书写命名总结 ...
- 程序员练级攻略(2018)-陈皓-笔记整理
程序员练级攻略(2018) 开篇词 入门篇 零基础启蒙 正式入门 修养篇 程序员修养 专业基础篇 编程语 ...
- methanol 模块化的可定制的网页爬虫软件,主要的优点是速度快。
methanol模块化的可定制的网页爬虫软件,主要的优点是速度快. 下载:http://sourceforge.net/projects/methabot/?source=typ_redirect R ...
- 【原创】【推荐】《ASP.NET 3.5+SQL Server网站模块化开发全程实录》出版记
进过半年多的努力,<ASP.NET 3.5+SQL Server网站模块化开发全程实录>一书终于得以由清华大学出版社顺利出版. 第一次出版此类图书,不免其中会有诸多纰漏,还望广大读者不吝指 ...
最新文章
- html设置表格平分,如果未知数量,如何在HTML表格中均匀分配列宽?
- 第一行代码学习笔记第四章——探究碎片
- JAVA语言基础-面向对象(IO:IO字符流、递归)
- ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘
- Magento模块开发之数据库SQL操作方法说明
- 机器学习实战(四)逻辑回归LR(Logistic Regression)
- Android工具栏中心标题和自定义字体
- InnoDB中Adaptive hash index存在问题、Percona改进及一个bug
- 神经网络+CNN模型训练总结:
- 翻译:如何在Mac OS X中设置文件权限chmod
- 计算机博弈的代码java,Java 速成
- 计算机主板型号尺寸,10大华硕主板型号简介,组装电脑的朋友可别错过
- JavaScript网页游戏开发实战视频教程
- 修正的判定/条件覆盖
- html在js中为添加监听,使用addeventlistener为js动态创建的元素添加事件监听
- 一江春水向东流 任正非
- 《蔡康永的说话之道》思维导图学习笔记
- Huilder连接Android逍遥模拟器
- vue,的M、V、VM分别代表什么
- 话费对接充值平台_手机话费误充给他人怎么办?小编带你找运营商要回来