数字化互联网时代机遇与挑战带给运营商的机遇有哪些

您所在的位置: &
JavaScript模块化:使用requireJS按需加载
JavaScript模块化:使用requireJS按需加载
主流的JS模块加载器有requireJS,SeaJS等,加载器之间可能会因为遵循的规范不同有微妙的差别,从纯用户的角度出发,之所以选requireJS而不是SeaJS主要是因为:功能实现上两者相差无几,没有明显的性能差异或重大问题。文档丰富程度上,requireJS远远好于SeaJS。
模块加载器的概念可能稍微接触过前端开发的童鞋都不会陌生,通过模块加载器可以有效的解决这些问题:
JS文件的依赖关系。
通过异步加载优化script标签引起的阻塞问题
可以简单的以文件为单位将功能模块化并实现复用
主流的JS模块加载器有,等,加载器之间可能会因为遵循的规范不同有微妙的差别,从纯用户的角度出发,之所以选requireJS而不是SeaJS主要是因为:
功能实现上两者相差无几,没有明显的性能差异或重大问题。
文档丰富程度上,requireJS远远好于SeaJS,就拿最简单的加载jQuery和jQuery插件这回事,虽然两者的实现方法相差无几, 但requireJS就有可以直接拿来用的Demo,SeaJS还要读文档自己慢慢折腾。一些问题的解决上,requireJS为关键词也更容易找到答 案。
requireJS 加载jQuery + jQuery插件
可能对于一般Web App来说,引入jQuery及相关插件的概率是最大的,requireJS也亲切的给出了相应的解决方案及的文档及。
在最新的jQuery1.9.X中,jQuery已经在最后直接将自己注册为一个,即是说可以直接被requireJS作为模块加载。如果是加载旧版的jQuery有两种方法:
1. 让jQuery先于requireJS加载
2. 对jQuery代码稍做一点处理,在jQuery代码包裹一句:
define([&jquery&],&function($)&{&&&&&&});&
requireJS的示例中,直接将requireJS与jQuery合并为一个文件,如果是采用jQuery作为核心库的话推荐这种做法。
同样对于jQuery插件来说也有两种方法
1. 在插件外包裹代码
define([&jquery&],&function($){&&&&&&&});&
2. 在使用reuqireJS代码加载前注册插件(比如在main.js)中
requirejs.config({&&&&&&shim&:&{&&&&&&&&&&jquery-cookie&&&:&[&jquery&]&&&&&}&});&
requireJS加载第三方类库
在实例的App中还用到了jQuery以外的第三方类库,如果类库不是一个标准的AMD模块而又不想更改这些类库的代码,同样需要提前进行定义:
require.config({&&&&&&&paths:&{&&&&&&&&&&&&&'underscore':&'vendor/underscore'&&&&&&&},&&&&&&&shim:&{&&&&&&&&&&&underscore:&{&&&&&&&&&&&&&&&exports:&'_'&&&&&&&&&&&}&&&&&&&}&});&
CSS文件的模块化处理
在requireJS中,模块的概念仅限于JS文件,如果需要加载图片、JSON等非JS文件,requireJS实现了一系列。
但是遗憾的是requireJS官方没有对CSS进行模块化处理,而我们在实际项目中却往往能遇到一些场景,比如一个轮播的图片展示栏,比如高级编辑器等等。几乎所有的富UI组件都会由JS与CSS两部分构成,而CSS之间也存在着模块的概念以及依赖关系。
为了更好的与requireJS整合,这里采用来解决CSS的模块化与依赖问题。
require-css是一个requireJS插件,下载后将css.js与normalize.js放于main.js同级即可默认被加载,比如在我们的项目中需要加载jQuery Mobile的css文件,那么可以直接这样调用:
require(['jquery',&'css!../css/jquery.mobile-1.3.0.min.css'],&function($)&{&});&
不过由于这个CSS本质上是属于jQuery Mobile模块的一部分,更好的做法是将这个CSS文件的定义放在jQuery Mobile的依赖关系中,最终我们的requireJS定义部分为:
require.config({&&&&&&&paths:&{&&&&&&&&&&&&&'jquerymobile':&'vendor/jquery.mobile-1.3.0',&&&&&&&&&&&&&'jstorage'&:&'vendor/jstorage',&&&&&&&&&&&&&'underscore':&'vendor/underscore'&&&&&&&},&&&&&&&shim:&{&&&&&&&&&&&jquerymobile&:&{&&&&&&&&&&&&&deps:&[&&&&&&&&&&&&&&&&&'css!../css/jquery.mobile-1.3.0.min.css'&&&&&&&&&&&&&]&&&&&&&&&&&},&&&&&&&&&&&underscore:&{&&&&&&&&&&&&&&&exports:&'_'&&&&&&&&&&&}&&&&&&&}&});&
在使用模块时,只需要:
require(['jquery',&'underscore',&'jquerymobile',&'jstorage'],&function($,&_)&{&});&
jQuery Mobile的CSS文件就会被自动加载,这样CSS与JS就被整合为一个模块了。同理其他有复杂依赖关系的模块也可以做类似处理,requireJS会解决依赖关系的逻辑。
数据源的加载与等待
Web App一般都会动态加载后端的数据,数据格式一般可以是JSON、JSONP也可以直接是一个JS变量。这里以JS变量为例:
var&restaurants&=&[&&&&&{&&&&&&&&&&name&:&&KFC&&&&&&},&&&&&{&&&&&&&&&&name&:&&7-11&&&&&&},&&&&&{&&&&&&&&&&name&:&&成都小吃&&&&&&}&]&
载入这段数据:
$.getScript('data/restaurants.json',&function(e){&&&&&var&data&=&window.&&&&&alert(data[0].name);&&});&
单一的数据源确实很简单,但是往往一个应用中会有多个数据源,比如在这个实例App中UI就需要载入用户信息、餐厅信息、订餐信息三种数据后才能工作。如果仅仅靠多层嵌套回调函数的话,可能代码的耦合就非常重了。
为了解决多个数据加载的问题,我习惯的解决方法是构造一个dataReady事件响应机制。
var&foodOrder&=&{&&&&&&&&&&&dataReadyFunc&:&[]&&&&&&&&&&&,&dataSource&:&[&&&&&&&&&{&url&:&'data/restaurants.json',&ready&:&false,&data&:&null&},&&&&&&&&&{&url&:&'data/users.json',&ready&:&false,&data&:&null&},&&&&&&&&&{&url&:&'data/foods.json',&ready&:&false,&data&:&null&}&&&&&]&&&&&&&&&&&,&isReady&:&function(){&&&&&&&&&var&isReady&=&true;&&&&&&&&&for(var&key&in&this.dataSource){&&&&&&&&&&&&&if(this.dataSource[key].ready&!==&true){&&&&&&&&&&&&&&&&&isReady&=&false;&&&&&&&&&&&&&}&&&&&&&&&}&&&&&&&&&return&isR&&&&&}&&&&&&&&&&&,&callReady&:&function(){&&&&&&&&&if(true&===&this.isReady()){&&&&&&&&&&&&&for(var&key&in&this.dataReadyFunc){&&&&&&&&&&&&&&&&&this.dataReadyFunc[key]();&&&&&&&&&&&&&}&&&&&&&&&}&&&&&}&&&&&&&&&&&,&dataReady&:&function(func){&&&&&&&&&if&(typeof&func&!==&'function')&{&&&&&&&&&&&&&return&false;&&&&&&&&&}&&&&&&&&&&this.dataReadyFunc.push(func);&&&&&}&&&&&&,&init&:&function(){&&&&&&&&&var&self&=&this;&&&&&&&&&var&_initElement&=&function(key,&url){&&&&&&&&&&&&&$.getScript(url,&function(e){&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&self.dataSource[key].data&=&window[key];&&&&&&&&&&&&&&&&&self.dataSource[key].ready&=&true;&&&&&&&&&&&&&&&&&self.callReady();&&&&&&&&&&&&&});&&&&&&&&&}&&&&&&&&&for(var&key&in&this.dataSource){&&&&&&&&&&&&&_initElement(key,&this.dataSource[key].url);&&&&&&&&&}&&&&&}&}&
foodOrder.dataReady(function(){&&&&alert(1);&&&&&&});&foodOrder.init();&
dataReady内的alert将会在所有数据载入完毕后开始执行。
这段处理的逻辑并不复杂,将所有要执行的方法通过dataReady暂存起来,等待数据全部加载完毕后再执行,更加复杂的场景此方法仍然通用。【编辑推荐】【责任编辑: TEL:(010)】
关于&&的更多文章
Android 4.4即将发布,这对大家来说都是很期待的,当然,无论是
随着云计算、物联网、大数据、移动互联网的大发展,你应该知道这些。
谷歌在新品发布会上正式发布了传闻已久的Android 4.3
App定价是开发者不可忽视的部分,它是确保应用高能见
微信自引入语音短信功能用户量爆发之后,发展状况一直
本书是根据全国计算机技术与软件专业技术资格(水平)考试《网络管理员考试大纲》所要求的考试范围而编写的试题集。全书共分10个
Windows Phone专家
Android开发专家
51CTO旗下网站本文的目的是为了能大让家更好的认识 Mod,之所以引入 RequireJS/SeaJS 的对比主要是应大家要求更清晰的对比应用场景,并不是为了比较出孰胜孰劣,RequireJS 和 SeaJS 都是模块化漫漫之路的先驱者,向他们致敬!
##为工程化为生的
模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,采用模块化可以让系统的可维护性更加简单易得。
JavaScript 并没有为开发者们提供以一种简洁、有条理地的方式来管理模块的方法。从出发点来看,和 RequireJS/SeaJS 是一致的,为开发者提供一套 JavaScript 模块化开发方案,让 JavaScript 的模块化开发变得更简单自然。但是在实现的过程中却存在巨大着的差异。
严格上来讲并不是一个独立的模块化框架,它是被设计用做模块化方案的 JavaScript 支持,需要和自动化工具、后端框架配合来使用,目的在于希望给工程师提供一个类似 nodeJS 一样的开发体验,同时具备很好的线上性能。
RequireJS 和 SeaJS 的定位主要是 Web 浏览器端的模块加载器,依靠 JavaScript 运行时来支持模块定义、依赖分析和加载等功能。
##类 CommonJS 的开发体验
RequireJS 遵守的是 AMD 规范,SeaJS 遵守的是 CMD 的规范。AMD/CMD 规范使用的是“异步模块定义”的方式,这种方式给开发带来了极大的不便,所有的同步代码都需要修改为异步的方式,我们是否可以在前端开发中使用“ CommonJS ”的方式,开发者可以使用自然、容易理解的模块定义和调用方式,不需要关注模块是否异步,不需要改变开发者的开发行为。答案当然是肯定的,并不完全遵守 AMD/CMD 规范,也正是为了为开发者提供更简单自然的开发体验。
###模块定义
Mod 使用 define 来定义一个模块:
define (id, factory)
factory 提供了 3 个参数:require, exports, module ,用于模块的引用和导出。
在平常开发中,我们无需关注模块定义,工具会自动对 JS 进行 define 包装处理:
//common/widget/menu/menu.js
var $ = require('common:widget/jquery/jquery.js');
exports.init = function() {
$('.menu-ui ul li a').click(function(event) {
var self = this;
$('.menu-ui ul li a.active').removeClass('active');
$(self).addClass('active');
event.preventDefault();
编译后代码
define('common:widget/menu/menu.js', function(require, exports, module){
var $ = require('common:widget/jquery/jquery.js');
exports.init = function() {
$('.menu-ui ul li a').click(function(event) {
var self = this;
$('.menu-ui ul li a.active').removeClass('active');
$(self).addClass('active');
event.preventDefault();
###模块调用
会在模块初始化之前自动加载相关依赖。因此当我们需要一个模块时,只需提供一个模块名即可获取:
require (id)
因为所需的模块都已预先加载,因此 require 可以立即(同步)返回该模块引用。无论在页面的 script 还是模块内部,工程师都可以放心通过 require 来加载模块,不需要考虑何时该使用同步接口何时调用异步接口。
##避免模块化引来的性能问题
RequireJS/SeaJS 通过过 JavaScript 运行时来支持“匿名闭包”、“依赖分析”和“模块加载”等功能,“依赖分析”需要在 JavaScript 运行时通过正则匹配到模块的依赖关系,然后顺着依赖链(也就是顺着模块声明的依赖层层进入,直到没有依赖为止)把所有需要加载的模块按顺序一一加载完毕,当模块很多、依赖关系复杂的情况下会严重影响页面性能。通过以下设计避免了如上问题:
通过工具自动添加 define 闭包,线上不需要支持匿名闭包
通过工具自动处理依赖,线上不需要动态处理依赖
通过后端模板自动插入 script,线上不需要通过前端框架进行模块加载
通过以上设计,极其精简,整个文件只有 100 多行,相比下 RequireJS 有 2000 多行,SeaJS 有将近 1000 行。
##避免模块化为打包部署带来的极大不便
通过 RequireJS/SeaJS 进行模块化开发后,合并静态资源(打包)将变得十分不方便和晦涩难懂,每个文件里只能有一个模块,无论是“ combo 插件”还是“ flush 插件”,都需要我们修改模块化调用的代码,这无疑是雪上加霜,工程师不仅需要在开发的时候关注模块定义,在调用的时候还需要关注在一个请求里面加载哪些模块比较合适,模块化的初衷是为了提高开发效率、降低维护成本,但我们发现这样的模块化方案实际上并没有降低维护成本,某种程度上来说使得整个项目更加复杂了。而使用 Mod,工程师只需要在配置文件配置合并策略即可,并不需要关注其他细节,会自动处理好依赖以及合并信息并在模块初始化之前将模块的静态资源以及所依赖的模块加载并准备好。
##自适应的性能优化
整个模块化流程如下:
通过自动化工具对模块进行编译处理,包括对对 JavaScript 模块添加闭包、记录每个静态资源的部署路径以及依赖关系并生成资源表(resource map),如下所示,
"demo.js": {
"uri": "/static/js/demo_33c5143.js",
"type": "js",
"demo.css"
"pkg": "p0"
"index.html": {
"uri": "/index.html",
"type": "html",
"demo.js",
"demo.css"
"script.js": {
"uri": "/static/js/script_32300bf.js",
"type": "js",
"pkg": "p0"
"uri": "/static/pkg/aio_5bb04ef.js",
"type": "js",
"demo.js",
"script.js"
"demo.css"
所有被打包的资源会有一个 pkg 属性 指向该表中的资源,而这个资源,正是我们配置的打包策略。有了这些信息,我们可以通过 Mod 框架(Mod 和后端框架)来管理和控制模块的加载。的模块化可以十分灵活的适应各种性能优化场景,我们还可以通过监控模块的调用情况,自动生成最优的打包配置,让网站可以自适应优化。
提供的是一体化的模块化解决方案,更多的是从工程化、自动化的角度去考虑,RequireJS/SeaJS 更独立灵活。
##相关阅读
作者: - F.I.S您现在的位置:&&>>&&>>&文章正文
河北经济日报 河北经济网 热线电话:5
JavaScript模块化规范
编辑:晓枫
Scrt模块化规范主要遵循CommonJS和AMD规范。
CommonJS规范-服务器端规范
Node.js是一个服务器端JavaScript项目,采用了CommonJS标准实现其模块系统。
CommonJS中采用一个全局require方法来加载模块,主要由原生模块module来实现和完成,该模块在启动时已经被加载。
模块主要分为两类:原生模块,文件模块。
1.原生模块
原生模块也是Node.js中最核心的模块。原生模块在Node.js源代码编译的时候编译进了二进制执行文件,加载的速度最快。
Node.js中存在许多原生模块,例如:http,net,os,path,fs, module等等,其引用方式为var fs = require('fs');
2.文件模块
文件模块是动态加载的,加载速度比原生模块慢。但是Node.js对原生模块和文件模块都进行了缓存,在第二次require该模块时,是不会有重复开销。
文件模块可细分为3类。这三类文件模块以文件后缀来区分,Node.js会根据后缀名来决定加载方法。
.js。通过fs模块同步读取js文件并编译执行。
.node。通常为npm安装的第三方模块。
.json。读取文件,调用JSON.parse解析加载。
虽然Node.js使用require方法引入模块的方式看似简单,但内部的加载却并不简单,且其中的优先级也不一样。
AMD规范-浏览器端JavaScript规范
CommonJS中模块存放在本地,使用同步方式加载模块,其加载时间基本相当于磁盘IO时间,这不会存在问题,但是如果环境是浏览器,则文件的加载受制于网络因素,如果网络加载比较慢,则可导致浏览器处于假死状态,因此浏览器端只能采用异步加载模块的方式。
AMD:Asynchronous Module Definition(异步模块定义)。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数:require([module], callback);
第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。目前,主要有两个Javascript库实现了AMD规范:require.js和curl.js。
require.js采用AMD规范实现模块加载,其采用define函数来定义。define函数接受两个参数,第一个参数为依赖数组,第二个参数为待定义的模块函数。如果没有依赖模块,则第一个参数也可以省略。
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
&&&&&&&&&&
河北经济日报社版权所有&未经允许不得复制或镜像&
本站由河北经济日报社全资子公司――河北易联文化传媒有限公司运营&
Email:&&qq:2015517&电话:5
冀ICP备字号&冀新网备&
河北经济日报社网络信息部设计制作
地址:石家庄市裕华西路186号
建议使用分辨率

我要回帖

更多关于 运营商数字化转型 的文章

 

随机推荐