Challenge-Me: JavaScript 包含引擎 - 第 III 部分






4.48/5 (21投票s)
实现 JavaScript 在其他 JavaScript 文件中包含 JavaScript 文件这一缺失的功能。
前言
这是文章的第三个也是最后一个部分,为了更好地理解这部分,我建议您先阅读第一部分和第二部分。
第三部分
来自前两部分
挑战
创建一个实现 JavaScript 在其他 JavaScript 文件中包含 JavaScript 文件这一缺失功能的引擎。
解决方案
一种仅当外部文件包含函数或不依赖于其他文件的声明时才有效,另一种解决方案在任何情况下都有效,但有一个小缺点:需要为源文件创建头文件。
第二个方案接近完成了挑战,但尚未完全实现。我们能做得更好吗?
解决方案 3
逻辑
当时发现的一个问题是,当脚本执行开始时,它会一直执行到底,因此我们有这样的限制:所有文件只能包含函数声明和对象声明(但仅限于不与其他文件中的对象相关的对象)。
理想情况下,只应执行包含 $include
函数的部分——我们将这部分命名为头文件,然后在合适的时候执行其余部分——正文。但如上所述,这是不可能的。
让我们再想想;如何停止脚本的执行?对于函数,您可以使用 return
,但对于整个脚本呢?
答案是:错误!!!当发生错误时,脚本的执行就会停止!所以我们故意抛出错误!下一个问题是:浏览器会显示错误吗?会的,除非我们重写 window.onerror
,使其不对用户显示任何内容。
我们的代码应该如下所示
$include = function ()
{
//code …
throw new Error(“Special Error”);
}
Window.onerror = function ()
{
//we can check here to see if the message
//of the error is not “Special Error”
//and then show it to the user
}
但是会出现两个问题
- 脚本执行后是否可以恢复?不行!(但我们可以重新执行它。)
- 另外,当发生合法错误时会怎样?可以显示吗?(可以,因为我们可以区分解析器错误和我们自己抛出的自定义错误。)
然而,还有一种更优雅的方法:使用 iFrame。
但是如何实现呢?一种方法是文本文件。然后,我们读取头文件(现在不一定必须是函数),然后使用 eval
来执行正文。如第一部分所述,eval
对资源的利用效率不高,因此不适合执行我们这样的代码块。
另一个问题是 IE 不会将 JavaScript 文件作为文本加载,而是要求您下载它。
因此,我们将有一个 HTML 文件,它会正常加载脚本,并且只执行 $include
函数,该函数会将当前 iFrame 中加载的文件的依赖项文件名传递给父文档,之后,我们将抛出错误。
此外,当文件加载时,它也会被缓存,当主文档需要时,不会再次从服务器加载。
但是,如果脚本没有依赖项(因此没有 $include
函数),会发生什么?
我们可以强制用户使用带有零参数的 $include()
吗?是的,我们可以。但我们也可以等到 script.onload
事件触发,然后告诉父文档该文件没有依赖项。
当然,还有另一个问题:脚本将被执行两次:一次在 iFrame 中,然后一次在主文档中;这已经是小问题了;代码中可能包含 alert、confirm、open 等,这些在 iFrame 中执行会严重破坏我们的工作。
还有另一个技巧:重写 window.alert
、window.open
、window.confirm
等,不仅让它们不起作用,而且还要停止脚本的执行。
似乎就是这样了!
让我们来回顾一下
主页面将包含一个文件树,该树是通过递归地将文件名 (filepath
) 传递给 iFrame 的文档来创建的,该文档将返回当前文件的依赖项。在这里,我们需要一个算法来检查循环依赖。当然,$include
函数在主页面中将不起任何作用。
之后,所有文件都可以按照正确的顺序添加到主文档的 head 中。
当然,我们会保留第一个解决方案中允许我们指定相对于 IncludingEngine.js 文件而不是当前 HTML 文档的路径的代码,以及从第二个解决方案中保留应用程序使用 Main
函数启动的方式。
实现
与前两个部分的实现不同,这个实现要大得多,因此不适合在此粘贴。但最重要的是已经在这里呈现了:整体思路以及克服不同障碍的小技巧。不过,您可以下载这个实现,然后进行检查。(别忘了,有两个文件:IncludingEngine.js 和 LoadFile.htm,它们共同完成了这项工作)。
下面的图表展示了该解决方案产生的产品的强大功能
该图表中未显示的关于最终产品的其他方面
- 它可以在线和离线工作。
- 不使用
eval
。 - 检测并显示形成循环依赖的文件。
现在我们可以说,第一部分中设定的挑战终于实现了。
注释
最新版本的实现可以在 IncludingEngine.jsFramework.com 找到。
这是“JavaScript 包含引擎”文章系列的所有部分:第一部分、第二部分、第三部分。此外,您可能想访问 IncludingEngine 网站以获取更多信息。