JS 以JRaiser Loader例子浅析Loader的实现原理

感兴趣的小伙伴,下面一起跟随编程之家 jb51.cc的小编来看看吧。,前段时间我开始基于SeaJS开发2.0版本的JRaiser,主要目的就是把这个库模块化。结合实际开发过程中遇到的问题,我重新写了一个更符合自身需求的JRaiser Loader以代替SeaJS(另一方面也是为了亲手写一个Loader)。与SeaJS一样,JRaiser Loader也是Wrappings规范(关于AMD与Wrappings的区别,这篇文章有详细说明)的实现,主要接口也与SeaJS保持一致(但功能暂时比SeaJS少)。
下面以JRaiser Loader的实现为例介绍一下Loader的实现原理。

先介绍几个术语:

模块:模块化开发中的一个功能单元。它有一个唯一的Id作为标识,并可以依赖于其他模块。
任务:全局require函数的回调函数。在JRaiser Loader的内部处理中,任务也是模块。
就绪:当某个模块已经加载完成,并且不依赖于任何模块或者它依赖的所有模块已经就绪,这个模块就是就绪状态。

在模块化开发中,一个模块可以依赖于任意个模块,而被它依赖的模块又可以依赖于任意个其他模块。这就要求加载模块时必须一层一层把所有依赖的模块都加载进来,类似于树的遍历。由于前端动态加载JS的过程是异步的,也就是说,这是异步的遍历。在算法上,JRaiser Loader采取自顶向下的遍历方式以及自底向上的通知方式。假设有A、B、C三个模块,A依赖于B,B依赖于C。当通过加载A模块时,其加载过程如下(红色箭头部分为异步流程):

JRaiser Loader的功能主要由四个类协作完成,其中最核心的是Module类。



Module对象有两种,一种表示功能接口模块,另一种表示需要执行的任务模块。前者通过define()创建,id为该模块的路径;后者通过全局的require函数创建,id为“#自动编号”。通过isTask方法可以知道该对象是否任务模块。

当加载模块定义文件时,该文件调用的define()就会创建Module对象。Module类的构造函数有三个参数:
id:模块的唯一标识,可以为空。
factory:模块的构造函数。
dependencies:依赖的模块,可以为空。

为何作为模块标识的id属性可以为空呢?这主要是浏览器特征决定的。前面提到过,模块路径即为模块Id。在IE下,只要遍历script元素,并找出readyState属性为interactive的元素,就可以获取到当前正在执行的script,进而通过src属性获取到它的路径;但是其他浏览器下的script元素没有readyState属性,就只能借助onload事件获取刚刚执行完的script元素(这招在IE下偏偏又是无效的,因为IE的onload事件有可能不是紧接着script执行结束触发的),所以延迟了Id的设置。

Module对象的初始化工作大多要在设置了Id之后才能进行,所以放到了setId方法中。setId方法会检查每个依赖模块是否就绪,如果未就绪,则调用dependentChain.add()添加依赖记录,并调用Module.load()加载该模块,Module.load则调用scriptLoader.load加载外部JS文件,此为自顶向下的模块加载流程。由于scriptLoader内部记录了文件加载状态,所以同一个文件不会被重复加载多次。最后,setId方法会调用_checkReady方法检查当前模块是否就绪。

一旦某Module对象已经就绪,它会执行以下操作:

如果该Module对象是功能接口模块,它会通过dependentChain.get()寻找依赖于它的Module对象,并逐一调用它们的notifyReady方法,告诉它们“我已经就绪”。
如果该Module对象是任务模块,它并不会调用execute方法立刻执行,而是调用taskManager.tryExecute()尝试执行任务队列。因为在任务队列里面,可能还有未就绪的任务在它的前面,如果立刻执行当前任务,那顺序就乱了。

另外,notifyReady方法也会调用_checkReady方法检查当前Module对象是否就绪,如果就绪,则对当前对象再执行上面的操作。此为自底向上的就绪通知流程。

至此,基本的加载流程已经完成。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)