博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《JavaScript框架设计》——2.2 加载器所在路径的探知
阅读量:7047 次
发布时间:2019-06-28

本文共 3655 字,大约阅读时间需要 12 分钟。

本节书摘来自异步社区《JavaScript框架设计》一书中的第2章,第2.2节,作者:司徒正美著,更多章节内容可以访问云栖社区“异步社区”公众号查看

2.2 加载器所在路径的探知

要加载一个模块,我们需要一个URL作为加载地址,一个script作为加载媒介。但用户在require时都用ID,因此我们需要一个将ID转换为URL的方法。思路很简单,强加个约定,URL的合成规则为。

basePath + 模块ID + ".js"

由于浏览器自上而下分析DOM,当浏览器在解析我们的JavaScript文件(这个JavaScript文件是指加载器)时,它就肯定DOM树中最后加入的script标签。因此,我们有下面这个方法。

function getBasePath() {    var nodes = document.getElementsByTagName("script");    var node = nodes[nodes.length - 1];    var src = document.querySelector ? node.src : node.getAttribute("src", 4);    return src;}

这个能满足99%的需求。但如果我们不得不动态加载我们的加载器呢?在旧版本下IE就会折戟沉沙,这个不奇怪,许多常规方法在IE6、IE7、IE8都失效,除了API的差异性,还有它本身的各种Bug。这个我很难指出是什么,总之要解决。如下面的这个JavaScript片断。

这时就需要用readyChange属性,微软在document、image、xhr、script等东西都拥有了这个属性,用来查看加载情况。

function getBasePath() {    var nodes = document.getElementsByTagName("script");    if (window.VBArray) {//如果是IE        for (var i = 0, node; node = nodes[i++]; ) {            if (node.readyState === "interactive") {                break;            }        }    } else {        node = nodes[nodes.length - 1];    }    var src = document.querySelector ? node.src : node.getAttribute("src", 4);    return src;}

这样就搞定了。现在想一下能否优化。访问DOM比一般的JavaScript代码消耗高许多。这时我们可以利用Error对象。

function getBasePath() {    try {        a.b.c()    } catch (e) {        if (e.fileName) {//firefox            return e.fileName;        } else if (e.sourceURL) {//safari            return e.sourceURL;        }    }    var nodes = document.getElementsByTagName("script");    if (window.VBArray) {//倒序查找更快        for (var i = nodes.length, node; node = nodes[--i]; ) {            if (node.readyState === "interactive") {                break;            }        }    } else {        node = nodes[nodes.length - 1];    }    var src = document.querySelector ? node.src : node.getAttribute("src", 4);    return src;}

当然Opera与Chrome也有一些属性可以供我们提取,但比较复杂,这里就略去了。

为了方便以后使用,我们先将mass.js这个去掉吧。在现实中,为了防止缓存,这个后面可能带版本号、时间戮什么的,也要去掉。

url = url.replace(/[?#].*/, "").slice(0, url.lastIndexOf("/") + 1);

在mass并行加载器中,有一个getCurrentScript方法,它用于取得正在被解析的JavaScript文件的src,而不局限于加载器的JavaScript地址。这个对实现匿名模块非常有用。想象一下,我们有个require(["a","b","c","d","e"], callback),这些模块在define里面都没有ID,识别哪一个模块是对应哪个JavaScript文件加载非常麻烦。或者使用iframe,将各个模块的加载独立于一个沙箱环境中,或者使用一些变量做标识(这存在被覆盖的危险),因此mass再次发掘Error对象的私有属性。

function getCurrentScript(base) {//为true时相当于getBasePath    var stack;    try { //Firefox可以直接 var e = new Error("test"),但其他浏览器只会生成一个空Error        a.b.c(); //强制报错,以便捕获e.stack    } catch (e) { //Safari的错误对象只有line、sourceId、sourceURL        stack = e.stack;        if (!stack && window.opera) {            //Opera 9没有e.stack,但有e.Backtrace,不能直接取得,需要对e对象转字符串进行抽取            stack = (String(e).match(/of linked script \S+/g) || []).join(" ");        }    }    if (stack) {        /**e.stack最后一行在所有支持的浏览器大致如下。         *Chrome23:         * at http://113.93.50.63/data.js:4:1         *Firefox17:         *@http://113.93.50.63/query.js:4         *@http://113.93.50.63/data.js:4         *IE10:         *  at Global code (http://113.93.50.63/data.js:4:1)         *  //firefox4+ 可以用document.currentScript         */        stack = stack.split(/[@ ]/g).pop();   //取得最后一行,最后一个空格或@之后的部分        stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "");                //去掉换行符        return stack.replace(/(:\d+)?:\d+$/i, ""); //去掉行号与或许存在的出错字符起始位置    }    ///我们在动态加载模块时,节点都插入head中,因此只在head标签中寻找    var nodes = (base ? document : head).getElementsByTagName("script");    for (var i = nodes.length, node; node = nodes[--i]; ) {        if ((base || node.className === moduleClass) && node.readyState === "interactive") {            return node.className = node.src;        }//如果此模块加载过就重写className    }}

转载地址:http://rbuol.baihongyu.com/

你可能感兴趣的文章
最新勒索软件病毒防范方法及措施
查看>>
cJSON精度丢失问题
查看>>
从配置文件的格式扯到GUI和CLI
查看>>
U盘安装系统提示Ghost has detected corruption in the image解决方法
查看>>
通过Powershell重新挂接父VHD磁盘的方法
查看>>
date命令[原创]
查看>>
Rsync完全配置
查看>>
系统监控工具----Inotify-Tools
查看>>
由浅入深CIL系列:2.CIL的基本构成+CIL操作码速记表+CIL操作码大全速查
查看>>
Net设计模式实例之组合模式(Composite Pattern)(2)
查看>>
duplicate symbol _GAD_MD5
查看>>
mysql编译报错: No curses/termcap library found
查看>>
Shell脚本之sed篇
查看>>
学习 Kubernetes 的 Why 和 How - 每天5分钟玩转 Docker 容器技术
查看>>
维护人员应该掌握的代码
查看>>
编写脚本时以年月日为目录时值得注意的地方
查看>>
proftpd+ssl安装及使用
查看>>
利用自反ACL实现VLAN之间的单向访问
查看>>
mysql 修改表结构操作
查看>>
日志分析工具Awstats实战之Nginx篇-分析结果静态化
查看>>