【requireJS路径加载】与程序员小卡的交流
这两天正好看到了程序员小卡同学的一篇博客,里面对requireJS路径的解析做了一些说明,里面有点问题待解决,我这里正好知道一点,所以整理成文,不知对小卡同学是否有帮助。
- requirejs.config({
- baseUrl: 'js'
- });
- // 依赖lib.js,实际加载的路径是 js/common/lib.js,而lib模块又依赖于util模块('./util'),解析后的实际路径为 js/common/util.js
- require(['common/lib'], function(Lib){
- Lib.say('hello');
- });
- // 依赖util模块
- define(['./util'], function(Util){
- return {
- say: function(msg){
- Util.say(msg);
- }
- };
- });
若是变个写法,util的目录结构就变了
- requirejs.config({
- baseUrl: 'js',
- paths: {
- lib: 'common/lib'
- }
- });
- // 实际加载的路径是 js/common/lib.js
- require(['lib'], function(Lib){
- Lib.say('hello');
- });
- // util模块解析后的路径为 js/util.js
- define(['./util'], function(Lib){
- return {
- say: function(msg){
- Lib.say(msg);
- }
- };
- });
我们今天便一起来学习下这个问题
requireJS的basePath

简单requireJS流程
- require(['common/lib'], function(Lib){
- Lib.say('hello');
- });
该代码会在require内部执行过程中,具有第一个依赖项,这个依赖项是'common/lib',他的键值便是这个了
这里会首先加载器依赖项,common/lib,而此时便会做第一步的解析并且形成一个模块
在模块加载时,会创建一个script标签,并且为其绑定load事件,这里会有第二个事件的触发
② 在加载common/lib模块时,有一个关键点需要注意:
- 文件加载结束便会马上执行,所以其define方法执行了,并且往globalDefQueue写入了数据
- load事件触发,会创建一个requireJS module,这个时候其依赖项会加载
上述虽然与本次讨论的东西无关,却是理解整个require的关键,各位可以去看看
③ context.completeLoad(data.id) =>但是这个时候却发现其有一个依赖项,于是便会先加载器依赖项,这里又会进入,main.js中require的逻辑,即这段代码:
- //Enable each dependency
- each(this.depMaps, bind(this, function (depMap, i) {
- var id, mod, handler;
- if (typeof depMap === 'string') {
- //Dependency needs to be converted to a depMap
- //and wired up to this module.
- depMap = makeModuleMap(depMap,
- (this.map.isDefine ? this.map : this.map.parentMap),
- false,
- !this.skipMap);
- this.depMaps[i] = depMap;
- handler = getOwn(handlers, depMap.id);
- if (handler) {
- this.depExports[i] = handler(this);
- return;
- }
- this.depCount += 1;
- on(depMap, 'defined', bind(this, function (depExports) {
- this.defineDep(i, depExports);
- this.check();
- }));
- if (this.errback) {
- on(depMap, 'error', bind(this, this.errback));
- }
- }
- id = depMap.id;
- mod = registry[id];
- //Skip special modules like 'require', 'exports', 'module'
- //Also, don't call enable if it is already enabled,
- //important in circular dependency cases.
- if (!hasProp(handlers, id) && mod && !mod.enabled) {
- context.enable(depMap, this);
- }
- }));
这是非常关键的一段代码,无论里面的depcount还是其中的on defined事件点注册皆十分关键
从这里开始会加载util相关资源,于是util进入了相关加载流程了,这也是小卡关注的地方
但是这里有一个不一样的地方是,util模块时具有parentModuleMap的,而common/lib不具有
这里util与lib有一个映射关系lib->util,所以util的parentName就是common/lib
这个时候就到了解析URL这个步骤了
- //name=>./util; parentName=>common/lib
- normalizedName = normalize(name, parentName, applyMap);
我们要做的事情就是解析这个地址
- /**
- * Given a relative module name, like ./something, normalize it to
- * a real name that can be mapped to a path.
- * @param {String} name the relative name
- * @param {String} baseName a real name that the name arg is relative
- * to.
- * @param {Boolean} applyMap apply the map config to the value. Should
- * only be done if this normalization is for a dependency ID.
- * @returns {String} normalized name
- */
- function normalize(name, baseName, applyMap) {
- var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, normalizedBaseParts, baseParts = (baseName && baseName.split('/')),
- map = config.map,
- starMap = map && map['*'];
- //Adjust any relative paths.
- if (name) {
- name = name.split('/');
- lastIndex = name.length - 1;
- // If wanting node ID compatibility, strip .js from end
- // of IDs. Have to do this here, and not in nameToUrl
- // because node allows either .js or non .js to map
- // to same file.
- if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
- name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
- }
- // Starts with a '.' so need the baseName
- if (name[0].charAt(0) === '.' && baseParts) {
- //Convert baseName to array, and lop off the last part,
- //so that . matches that 'directory' and not name of the baseName's
- //module. For instance, baseName of 'one/two/three', maps to
- //'one/two/three.js', but we want the directory, 'one/two' for
- //this normalization.
- normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
- name = normalizedBaseParts.concat(name);
- }
- trimDots(name);
- name = name.join('/');
- }
- //Apply map config if available.
- if (applyMap && map && (baseParts || starMap)) {
- nameParts = name.split('/');
- outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
- nameSegment = nameParts.slice(0, i).join('/');
- if (baseParts) {
- //Find the longest baseName segment match in the config.
- //So, do joins on the biggest to smallest lengths of baseParts.
- for (j = baseParts.length; j > 0; j -= 1) {
- mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
- //baseName segment has config, find if it has one for
- //this name.
- if (mapValue) {
- mapValue = getOwn(mapValue, nameSegment);
- if (mapValue) {
- //Match, update name to the new value.
- foundMap = mapValue;
- foundI = i;
- break outerLoop;
- }
- }
- }
- }
- //Check for a star map match, but just hold on to it,
- //if there is a shorter segment match later in a matching
- //config, then favor over this star map.
- if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
- foundStarMap = getOwn(starMap, nameSegment);
- starI = i;
- }
- }
- if (!foundMap && foundStarMap) {
- foundMap = foundStarMap;
- foundI = starI;
- }
- if (foundMap) {
- nameParts.splice(0, foundI, foundMap);
- name = nameParts.join('/');
- }
- }
- // If the name points to a package's name, use
- // the package main instead.
- pkgMain = getOwn(config.pkgs, name);
- return pkgMain ? pkgMain: name;
- }
核心代码
PS:我看requireJS版本,又老了,他的代码又有更新啊!!!
上面这段代码是一个关键
- main.js=>require(['common/lib'], function (Lib)=>common/util
- main.js=>require(['lib'], function (Lib)=>util
- main.js=>require(['a/b/c/lib'], function (Lib)=>a/b/c/util
这里util是相对于父级的目录,这个是其地址变化的主要原因
所以,现在关于小卡的问题应该得到了解决,至于其map映射关系是如何形成的,这个话题就更加深了
小钗requireJS也是初学,很多不懂,不知是不是解决了小卡的问题,这里提出来各位高手一起看看,有误请提出。
【requireJS路径加载】与程序员小卡的交流的更多相关文章
- [转]微信小程序之加载更多(分页加载)实例 —— 微信小程序实战系列(2)
本文转自;http://blog.csdn.net/michael_ouyang/article/details/56846185 loadmore 加载更多(分页加载) 当用户打开一个页面时,假设后 ...
- 【requireJS源码学习03】细究requireJS的加载流程
前言 这个星期折腾了一周,中间没有什么时间学习,周末又干了些其它事情,这个时候正好有时间,我们一起来继续学习requireJS吧 还是那句话,小钗觉得requireJS本身还是有点难度的,估计完全吸收 ...
- 【程序员小助手】Synergy,感受穿越屏幕之美
内容简介 1.Synergy简介 2.Synergy安装与配置 3.附录 [程序员小助手]系列 在这个系列文章中(不定期更新),小编会把这些年(也没几年)的编程学习和工作中使用到的个人感觉非常好的软件 ...
- 【程序员小助手】Emacs,最强编辑器,没有之一
内容简介 1.Emacs简介 2.Emacs三个平台的安装与配置 3.自动补全插件 4.小编的Emacs配置文件 5.常用快捷方式 6.和版本控制系统的配合(以SVN为例) [程序员小助手]系列 在这 ...
- AngularJS + ui-router + RequireJS异步加载注册controller/directive/filter/service
一般情况下我们会将项目所用到的controller/directive/filter/sercive预先加载完再初始化AngularJS模块,但是当项目比较复杂的情况下,应该是打开对应的界面才加载对应 ...
- Oracle直接路径加载--append的深度解析
㈠ 直接路径加载和buffer cache 直接路径插入的数据不经过buffer cache,从PGA直接把数据格式化成Oracle块 然后由普通的Oracle ...
- 程序员小张的第一篇博文 --记Markdown的使用学习
1.前言 为了即将到来的面试做准备,以及记录一下平日里自己的学习过程和生活日常,我开始进驻博客园啦!这就是我的第一篇博客(有点小激动)~ 作为一只新手,首先记录一下今晚的编写博文的学习过程吧~ 2.使 ...
- jQuery自动加载更多程序
1.1.1 摘要 现在,我们经常使用的微博.微信或其他应用都有异步加载功能,简而言之,就是我们在刷微博或微信时,移动到界面的顶端或低端后程序通过异步的方式进行加载数据,这种方式加快了数据的加载速度,由 ...
- 用UBOOT自带loadb命令加载应用程序到SDRAM中运行的方法
S3C44B0开发板中,用UBOOT自带loadb命令加载应用程序到SDRAM中运行的方法 1.开发板说明: 开发板上已有移植好的UBOOT运行. 2.交叉编译工具链为arm-linu-g ...
随机推荐
- 谈谈关键字strictfp
Java语言中的其中一个设计目标是可移植性.无论在哪个虚拟机上运行,同一个计算应该得到同样的结果.对于浮点数的算术运算,实现这样的可移植性是相当困难的.double 类型使用 64 位存储一个 do ...
- OpenCASCADE Performance Test
OpenCASCADE Performance Test eryar@163.com Abstract. Use the Draw Test Harness to test the performan ...
- Android使用TextureView播放视频
1.引言 如果你想显示一段在线视频或者任意的数据流比如视频或者OpenGL 场景,你可以用android中的TextureView做到. 1).TextureView的兄弟SurfaceView 应用 ...
- Android随笔之——Activity中启动另一应用
最近在写语音交互程序,在语音打开应用这块碰到如何用代码控制应用启动的问题.百度了一下,有两种方案:1.获取应用的包名:2.获取应用的包名.入口类名. 之前对两种方案都进行了尝试,发现方案二中存在一个弊 ...
- 基于讯飞语音API应用开发之——离线词典构建
最近实习在做一个跟语音相关的项目,就在度娘上搜索了很多关于语音的API,顺藤摸瓜找到了科大讯飞,虽然度娘自家也有语音识别.语义理解这块,但感觉应该不是很好用,毕竟之前用过百度地图的API,有问题也找不 ...
- EntityFramework DbContext 线程安全
先看这一段异常信息: A second operation started on this context before a previous asynchronous operation compl ...
- Flume NG Getting Started(Flume NG 新手入门指南)
Flume NG Getting Started(Flume NG 新手入门指南)翻译 新手入门 Flume NG是什么? 有什么改变? 获得Flume NG 从源码构建 配置 flume-ng全局选 ...
- win7系统下如何配置php-Apache-mysql环境
如何在win7系统下配置php环境呢,php+Apache+mysql都是在配置过程中必不可少的元素,php负责解析php代码,apache负责服务器端而mysql是数据交互的中转站. 那么如何将ph ...
- kafka源码分析之二客户端分析
客户端由两种:生产者和消费者 1. 生产者 先看一下生产者的构造方法: private KafkaProducer(ProducerConfig config, Serializer<K> ...
- CSS浮动文摘
很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 写在前面的话: 由于CSS内容比较多,没有精力从头到尾讲一遍,只能有 ...