亚游,  中国顶级航空制造商中国航空工业集团公司(AVIC)展示了新型GCS(地面控制站),用大屏幕全息图显示无人机的飞行姿态,看起来就像是制作精良的电子游戏,其他人可以并借此学习控制无人机飞行。

中国南海研究院院长吴士存12日接受《环球时报》记者采访时表示,随着中菲关系转圜,这笔交易说明两国关系到了一定水平,不过,还要看是什么武器,如果像中国向巴基斯坦和一些非洲国家出售护卫舰和其他武器一样,才可能说明双方在安全、政治领域达到较高水平。而且,从深层次的军事领域合作看,特别是杀伤型武器,菲律宾还受制于《美菲共同防御条约》等条约的限制。他认为,不排除菲律宾方面在有意做给美国看。在农村养殖什么赚钱  中关村管委会副主任宣鸿表示,面向未来,中关村要按照国家侧结构性改革和创新驱动发展的战略决策,根据北京市加强全国科技创新中心建设的重大部署,着力深化全面创新改革,积极优化创新创业生态系统,努力率先建成具有全球影响力的科技创新中心。

发布于 2018-03-23 17:58:27 | 115 次阅读 | 评论: 0 | 来源: 网友投递

这里有新鲜出炉的精品教程,程序狗速度看过来!


本篇文章主要介绍了深入理解requireJS-实现一个简单的模块加载器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

在前文中我们不止一次强调过模块化编程的重要性,以及其可以解决的问题:

① 解决单文件变量命名冲突问题

② 解决前端多人协作问题

③ 解决文件依赖问题

④ 按需加载(这个说法其实很假了)

⑤ ......

为了深入了解加载器,中间阅读过一点requireJS的源码,但对于很多同学来说,对加载器的实现依旧不太清楚

事实上不通过代码实现,单单凭阅读想理解一个库或者框架只能达到一知半解的地步,所以今天便来实现一个简单的加载器

加载器原理分析

分与合

事实上,一个程序运行需要完整的模块,以下代码为例:


/求得绩效系数
 var performanceCoefficient = function () {
  return 0.2;
 };

 /住房公积金计算方式
 var companyReserve = function (salary) {
  return salary * 0.2;
 };

 /个人所得税
 var incomeTax = function (salary) {
  return salary * 0.2;
 };

 /基本工资
 var salary = 1000;

 /最终工资
 var mySalary = salary + salary * performanceCoefficient();
 mySalary = mySalary - companyReserve(mySalary) - incomeTax(mySalary - companyReserve(mySalary));
 console.log(mySalary);

我一份完整的工资来说,公司会有绩效奖励,但是其算法可能非常复杂,其中可能涉及到出勤率,完成度什么的,这里暂时不管

而有增便有减,所以我们会交住房公积金,也会扣除个人所得税,最终才是我的工资

对于完整的程序来说上面的流程缺一不可,但是各个函数中却有可能异常的复杂,跟钱有关系的东西都复杂,所以单单是公司绩效便有可能超过1000行代码

于是我们这边便会开始分:


<script src="companyReserve.js" type="text/javascript"></script>
<script src="incomeTax.js" type="text/javascript"></script>
<script src="performanceCoefficient.js" type="text/javascript"></script>
<script type="text/javascript">

 /基本工资
 var salary = 1000;

 /最终工资
 var mySalary = salary + salary * performanceCoefficient();
 mySalary = mySalary - companyReserve(mySalary) - incomeTax(mySalary - companyReserve(mySalary));
 console.log(mySalary);

</script>

上面的代码表明上是“分”开了,事实上也造成了“合”的问题,我要如何才能很好的把它们重新合到一起呢,毕竟其中的文件可能还涉及到依赖,这里便进入我们的require与define

require与define

事实上,上面的方案仍然是以文件划分,而不是以模块划分的,若是文件名发生变化,页面会涉及到改变,其实这里应该有一个路径的映射处理这个问题


var pathCfg = {
 'companyReserve': 'companyReserve',
 'incomeTax': 'incomeTax',
 'performanceCoefficient': 'performanceCoefficient'
};

于是我们一个模块便对应了一个路径js文件,剩下的便是将之对应模块的加载了,因为前端模块涉及到请求。所以这种写法:


companyReserve = requile('companyReserve');

对于前端来说是不适用的,就算你在哪里看到这样做了,也一定是其中做了一些“手脚”,这里我们便需要依据AMD规范了:


require.config({
 'companyReserve': 'companyReserve',
 'incomeTax': 'incomeTax',
 'performanceCoefficient': 'performanceCoefficient'
});

require(['companyReserve', 'incomeTax', 'performanceCoefficient'], function (companyReserve, incomeTax, performanceCoefficient) {
 /基本工资
 var salary = 1000;

 /最终工资
 var mySalary = salary + salary * performanceCoefficient();
 mySalary = mySalary - companyReserve(mySalary) - incomeTax(mySalary - companyReserve(mySalary));
 console.log(mySalary);
});

这里便是一个标准的requireJS的写法了,首先定义模块以及其路径映射,其中定义依赖项


require(depArr, callback)

一个简单完整的模块加载器基本就是这个样子了,首先是一个依赖的数组,其次是一个回调,回调要求依赖项全部加载才能运行,并且回调的参数便是依赖项执行的结果,所以一般要求define模块具有一个返回值

方案有了,那么如何实现呢?

实现方案

说到模块加载,人们第一反应都是ajax,因为无论何时,能拿到模块文件的内容,都是模块化的基本,但是采用ajax的方式是不行的,因为ajax有跨域的问题

而模块化方案又不可避免的要处理跨域的问题,所以使用动态创建script标签加载js文件便成为了首选,但是,不使用ajax的方案,对于实现难度来说还是有要求

PS:我们实际工作中还会有加载html模板文件的场景,这个稍候再说

通常我们是这样做的,require作为程序入口,调度javascript资源,而加载到各个define模块后,各个模块便悄无声息的创建script标签加载

加载结束后便往require模块队列报告自己加载结束了,当require中多有依赖模块皆加载结束时,便执行其回调

原理大致如此,剩下的只是具体实现,而后在论证这个理论是否靠谱即可

加载器阉割实现

核心模块

根据以上理论,我们由整体来说,首先以入口三个基本函数来说


var require = function () {
};
require.config = function () {
};
require.define = function () {
};

这三个模块比不可少:

① config用以配置模块与路径的映射,或者还有其他用处

② require为程序入口

③ define设计各个模块,响应require的调度

然后我们这里会有一个创建script标签的方法,并且会监听其onLoad事件

④ loadScript

其次我们加载script标签后,应该有一个全局的模块对象,用于存储已经加载好的模块,于是这里提出了两个需求:

⑤ require.moduleObj 模块存储对象

⑥ Module,模块的构造函数

有了以上核心模块,我们形成了如下代码:


(function () {

 var Module = function () {
  this.status = 'loading'; /只具有loading与loaded两个状态
  this.depCount = 0; /模块依赖项
  this.value = null; /define函数回调执行的返回
 };


 var loadScript = function (url, callback) {

 };

 var config = function () {

 };

 var require = function (deps, callback) {

 };

 require.config = function (cfg) {

 };

 var define = function (deps, callback) {

 };

})();

于是接下来便是具体实现,然后在实现过程中补足不具备的接口与细节,往往在最后的实现与最初的设计没有半毛钱关系......

代码实现

这块最初实现时,本来想直接参考requireJS的实现,但是我们老大笑眯眯的拿出了一个他写的加载器,我一看不得不承认有点妖

于是这里便借鉴了其实现,做了简单改造:


(function () {

 /存储已经加载好的模块
 var moduleCache = {};

 var require = function (deps, callback) {
  var params = [];
  var depCount = 0;
  var i, len, isEmpty = false, modName;

  /获取当前正在执行的js代码段,这个在onLoad事件之前执行
  modName = document.currentScript && document.currentScript.id || 'REQUIRE_MAIN';

  /简单实现,这里未做参数检查,只考虑数组的情况
  if (deps.length) {
   for (i = 0, len = deps.length; i < len; i++) {
    (function (i) {
     /依赖加一
     depCount++;
     /这块回调很关键
     loadMod(deps[i], function (param) {
      params[i] = param;
      depCount--;
      if (depCount == 0) {
       saveModule(modName, params, callback);
      }
     });
    })(i);
   }
  } else {
   isEmpty = true;
  }

  if (isEmpty) {
   setTimeout(function () {
    saveModule(modName, null, callback);
   }, 0);
  }

 };

 /考虑最简单逻辑即可
 var _getPathUrl = function (modName) {
  var url = modName;
  /不严谨
  if (url.indexOf('.js') == -1) url = url + '.js';
  return url;
 };

 /模块加载
 var loadMod = function (modName, callback) {
  var url = _getPathUrl(modName), fs, mod;

  /如果该模块已经被加载
  if (moduleCache[modName]) {
   mod = moduleCache[modName];
   if (mod.status == 'loaded') {
    setTimeout(callback(this.params), 0);
   } else {
    /如果未到加载状态直接往onLoad插入值,在依赖项加载好后会解除依赖
    mod.onload.push(callback);
   }
  } else {

   /*
   这里重点说一下Module对象
   status代表模块状态
   onLoad事实上对应requireJS的事件回调,该模块被引用多少次变化执行多少次回调,通知被依赖项解除依赖
   */
   mod = moduleCache[modName] = {
    modName: modName,
    status: 'loading',
    export: null,
    onload: [callback]
   };

   _script = document.createElement('script');
   _script.id = modName;
   _script.type = 'text/javascript';
   _script.charset = 'utf-8';
   _script.async = true;
   _script.src = url;

   /这段代码在这个场景中意义不大,注释了
   /  _script.onload = function (e) {};

   fs = document.getElementsByTagName('script')[0];
   fs.parentNode.insertBefore(_script, fs);

  }
 };

 var saveModule = function (modName, params, callback) {
  var mod, fn;

  if (moduleCache.hasOwnProperty(modName)) {
   mod = moduleCache[modName];
   mod.status = 'loaded';
   /输出项
   mod.export = callback ? callback(params) : null;

   /解除父类依赖,这里事实上使用事件监听较好
   while (fn = mod.onload.shift()) {
    fn(mod.export);
   }
  } else {
   callback && callback.apply(window, params);
  }
 };

 window.require = require;
 window.define = require;

})();

首先这段代码有一些问题:

没有处理参数问题,字符串之类皆未处理

未处理循环依赖问题

未处理CMD写法

未处理html模板加载相关

未处理参数配置,baseUrl什么都没有搞

基于此想实现打包文件也不可能

......

但就是这100行代码,便是加载器的核心,代码很短,对各位理解加载器很有帮助,里面有两点需要注意:

① requireJS是使用事件监听处理本身依赖,这里直接将之放到了onLoad数组中了

② 这里有一个很有意思的东西


document.currentScript

这个可以获取当前执行的代码段

requireJS是在onLoad中处理各个模块的,这里就用了一个不一样的实现,每个js文件加载后,都会执行require(define)方法

执行后便取到当前正在执行的文件,并且取到文件名加载之,正因为如此,连script的onLoad事件都省了......

demo实现


<html xmlns="/www0b0aw30b0aorg/1999/xhtml">
<head>
 <title></title>
</head>
<body>
</body>
<script src="require.js" type="text/javascript"></script>
<script type="text/javascript">
 require(['util', 'math', 'num'], function (util, math, num) {

  num = math.getRadom() + '_' + num;
  num = util.formatNum(num);
  console.log(num);
 });
</script>
</html>

/util
define([], function () {
 return {
  formatNum: function (n) {
   if (n < 10) return '0' + n;
   return n;
  }
 };
});

/math
define(['num'], function (num) {
 return {
  getRadom: function () {
   return parseInt(Math.random() * num);
  }
 };
});

/math
define(['num'], function (num) {
 return {
  getRadom: function () {
   return parseInt(Math.random() * num);
  }
 };
});

小结

今天我们实现了一个简单的模块加载器,通过他希望可以帮助各位了解requireJS或者seaJS,最后顺利进入模块化编程的行列

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持phperz。



相关阅读 :
深入理解requireJS-实现一个简单的模块加载器
一个简单的动态加载js和css的jquery代码
概述如何实现一个简单的浏览器端js模块加载器
php实现一个简单的路由类
Python实现一个简单的MySQL类
使用Python实现一个简单的项目监控示例
用Python实现一个简单的线程池
仅用50行Python代码实现一个简单的代理服务器
用Python实现一个简单的能够发送带附件的邮件程序的教程
使用Python的Twisted框架实现一个简单的服务器
使用Python的Tornado框架实现一个简单的WebQQ机器人
用Python实现一个简单的多线程TCP服务器的教程
最新网友评论  共有(0)条评论 发布评论 返回顶部

Copyright © 2007-2017 亚游 All Rights Reserved   冀ICP备14009818号  亚游  广告服务
OPPO R15:不仅会拍照还懂音乐 “高薪招聘”实为运毒骗局 两男子运毒11斤落网 贪官帮他人拍地受贿 妻子“一句话”被送来进口车 10亿美元收购Ring后 亚马逊又投资一家智能家居厂商 英国警方:三名男子涉莱斯特爆炸事件被捕 美新税法前最后一次报税 个人如何避免罚款省税 山东主帅:场上局面大家看到了 赢的本该是我们 如同炼狱 韩世越号遇难者家属含泪拍下沉船内部照 东北大学56对校友回校举办集体婚礼 学校定制对戒 乐天百货回应撤出中国:有商讨对策 尚无具体方案 美国航母“抵近”,中国表现淡定的底气在这里 日政府宣布向阿富汗提供1310万美元 支援公正选举
夫妻结婚5年 偶然发现18年前曾意外合影同框(图) 财政部副部长朱光耀:贸易战对中美属于双输 又一位主帅下课!巩晓彬告别3年青岛执教生涯 世卫组织邀大家参会 台当局恼羞成怒呛声:没喊我 日本启动“远程办公周” 缓解东京奥运期间交通压力 U19贺岁杯-上港U19梯队4-1胜新疆天山雪豹夺冠 沪钢或进一步下探 区块链培训乱象:3天产出80个讲师 收费几百到几万 上海合作组织防长会议公报 积极评价俄在叙军事行动 汤杯前言4:谌龙再次担任一单 能否证明自己? 驳回申诉 关于“汤兰兰案”的这些细节你该知道 外交部长王毅:中美不必做对手 更需当伙伴
在远离喧嚣的亚布力 这些大佬们说了真心话 中国FC31战机将走向何方 能否成新一代舰载战斗机 俄罗斯开始禁止发布大选相关民调和预测结果 大学生用熊猫形象手绘班规:违者代领快递(图) 两家中国比特币矿机厂商计划在港IPO 各拟筹10亿美元 特朗普刚宣布帮农民搞了个大市场 欧盟打脸就来了 北京市常务副市长:京津冀半小时通行圈将初步形成 香港大学生为抵制普通话 冲进办公室恐吓老师(图) 死海水位年均下降约1.2米 水面缩减或2050年干涸 白手起家好项目 挣钱最多的行业 需要钱的的给我打电话 未来10年最赚钱行业 亚游