最近在开发一个非常复杂的需求,代码量巨大,为了清晰起见,必须拆分成多个JS文件,然后有序地组合起来。开发框架目前只支持将代码写在单个JS文件script.js中,因此需要修改。
考虑历史代码兼容性和开发周期,我决定采用一种简单的实现方案:文件包含。类似于C语言中的#include,我们在JS文件中做特殊标记,表明要将另一个JS文件的内容包含进来,然后在构建时用指定JS文件的内容替换这个特殊标记,这样就实现了分开编写、组合运行。
文件包含标记:在JS文件中用如下标记表明要包含哪个JS文件:
//#include: A/B/C/xxx.js
解析文件包含:
- 迭代解析:A包含B,B包含C,通过迭代算法可以实现正确的链式包含。算法:循环检查A中是否还有包含标记,有则对第一个包含标记(B)执行替换,此时,如果替换的内容中带进来了新的包含标记(C),则会在下一次循环中被解析。
- 防止循环包含:迭代解析的过程中,要记住走过的文件有哪些,一旦发现要包含的文件之前已经走过,就说明出现了循环包含,报错。
- 动态监听:一个脚本文件现在可以拆分为多个文件,这多个文件又随时可能修改、增加、删除,则对于持续构建模式来说,要监听变化的文件范围是动态的。每次构建一个脚本文件时,都要重新计算并监听涉及的文件。
有了文件包含机制,我们就可以获得以下好处:
- 将单个复杂的任务分解为多个简单的任务,提高了清晰度、可维护性。
- 可以实现公共代码,免于复制粘贴,提高了代码复用度。
- 在OA系统的代码块机制中,多个
<script src="...">之间的执行顺序是随机的,通过在同一个文件中控制文件包含的顺序,我们就可以严格控制多个脚本间的执行顺序。
文件包含机制也有其缺点:
- IDE不识别:标记是我们自己定的,IDE并不知道要包含哪个文件、文件间的顺序等信息,也就无法提供文件跳转、准确的代码提示等功能。
- 作用域不隔离:文件包含本质上是将代码拼在一起,是同一个作用域,并没有实现真正的JS模块化。编写代码时需要对这一点有清晰的认识,如果需要模块化,则必须自己用IIFE等手段实现。
- 不太容易理解:我开发的这个非常复杂的需求,其他同事在阅读代码时,不太容易跟踪和理解同一作用域、多层包含下的执行过程。
这些缺点,未来可以通过用Webpack实现真正的JS模块化来解决。