问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

requirejs 怎么模块化加载百度地图

发布网友 发布时间:2022-04-22 20:12

我来回答

2个回答

懂视网 时间:2022-04-23 00:34

本篇文章主要介绍了深入理解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="http://www.w3.org/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);
 }
 };
});

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

有关在Vue2.x中父组件与子组件双向绑定(详细教程)

详细介绍在Vue2.0中v-for迭代语法的变化(详细教程)

在vue2.0中循环遍历并且加载不同图片(详细教程)

热心网友 时间:2022-04-22 21:42

在直接访问后面这个网址,得到的就是真正的百度地图api文件了。
看起来好像直接转成 requirejs 加载的方式没有问题,那就试试?
// requirejs 的配置,因为百度地图是非AMD模式的,所以需要加上shim进行转换
require.config({
paths: {
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
门?049期父母欲其改娶五字金口决,开是什么特号生肖 支付宝怎么把银行卡的钱转到余额里呢? 下载wampserver5,安装并启动后不能启用apache、mysql的功能,请问这是怎... wampserver安装多个版本phpmysqlapache 四季豆有哪些吃法值得推荐? 四季豆牛肉馅饼的家常做法是什么? 香煎四季豆豆腐饼怎么做好吃 腾讯会议没声音怎么修复-腾讯会议没有声音修复办法 西安市高新区所有幼儿园 西安高新第二初级中学学区有哪些小区 windows 2003 sever ,sql 2008 SA与本地系统无法登录,SQLSERVER服务无法启动,错误提示17051 跪求《永不退缩2》网盘资源,是迈克尔·加·怀特主演的 求:电影永不退缩(Never Back Down) 第90分钟零7秒的时候,放的那首歌 久久金回收黄金多少钱? 介绍罗瑞卿用什么背景音乐 《警花与警犬》里每次执行任务的那个背景音乐是什么?纯音乐,节奏感 求never back down 是two steops。。唱的内个的歌曲链接 我有平安银行99.99黄金!想要卖出不知道最近的回收价格是多少?按2月11号今天回收价格是多少请高 时差计算公式! 为什么在关键线路上总时差等于自由时差 如何计算总时差? 自动档汽车一键正确的起步和停车步骤是什么? 二建管理的自由时差的计算箭尾节点为终点节点的工作,其自由时差 本工作自由时差=本工作总时差-紧后工作总时差的最小值? 单代号网络计划中自由时差(FF)如何计算? 施工管理中的自由时差和总是差的计算 自由时差与总时差的关系是什么? 自由时差和 总是差怎么计算 (工程)自由时差怎么计算? 自由时差的计算公式 求一部关于搏击的美国电影 跪求《永不退缩22(2011)》百度网盘高清资源在线观看,迈克尔·加·怀特主演的 有部电影:主人公原是一名橄榄球队员因滋事离开球队开始上学。期间认识了一女孩,去一聚会跟人搏击后败北 求MMA系列电影 搏击电影 男主角是一名大学生 他的父亲死于车祸 一首英文歌,求名字,歌词中好像有一句I don&#39;t never wanna wake up ,I don&#39;t never wanna with that way 虾和纯牛奶能一起吃吗 大虾和纯牛奶能一起吃吗 离职协议写结清工资实际没结 辞职了工资怎么结算? 员工提前离职工资结算规定 在上海自由贸易区内注册公司要怎么办 什么叫南向资金? 职业学校的官方该如何做? 南向资金是机构还是散户 requirejs怎样预加载脚本 澳大利亚三大国宝 有没有那个特别虐心的三角恋的电视剧最好结局是女主和男二在一起的那种 韩剧最好 谢谢 有哪些电视剧最后女一是和男二在一起 你希望哪部电视剧中的女主角和男二号在一起?