在Plain JS脚本之前和之后加载ES6模块依赖项

时间:2019-05-10 00:34:58

标签: javascript ecmascript-6 es6-modules

我有一个普通的JS脚本parser.js(由工具生成),该脚本依赖于ES6模块lexer.js中定义的变量。在我的ES6模块中,我已经将变量导出到window对象,因此可以从parser.js访问它们。但是,我需要在运行脚本之前以某种方式运行该ES6模块。而且似乎没有任何办法。

尝试1:在包含我的脚本之前尝试同步加载ES6模块

我在HTML中尝试了类似的方法。

    <script src="lexer.js" type="module"></script>
    <script src="parser.js"></script>

但是它似乎没有按顺序运行。 lexer.jsparser.js之后运行

尝试2:尝试在ES6模块内部同步加载脚本

我尝试像这样在解析器脚本周围创建包装器ES6模块

// use import to run the module and load variables into the window
import { lexer } from './lexer.js';

// load parser script synchronously
var req = new XMLHttpRequest();
req.open('GET', 'parser.js', false);
req.send(null);
eval(req.responseText);

但是,似乎不赞成使用同步XMLHttpRequest并且不再起作用(编辑:实际上,确实可以,请参见下面的my answer),而且我找不到其他方法来同步加载脚本。总的来说,我想说ES6模块系统和旧的javascript包含系统之间的不兼容性令人沮丧。

P.S。作为参考,我使用的代码生成工具是Nearley grammar compiler,它使我可以从语法中引用我的词法分析器,并生成一个普通的JS解析器。

编辑:@ yong-quan建议了一个整洁的解决方案,只需将defer放在脚本include标记中,例如

    <script src="lexer.js" type="module"></script>
    <script src="parser.js" defer></script>

似乎这只是将parser.js的执行推迟到了最后。但是,我没有提到我实际上有一个名为interpreter.js的ES6模块,需要在parser.js之后调用。抱歉,我没有提早一点,我认为无论哪种解决方案对我的第一个问题都起作用,也可以解决我的第二个问题。我更正了标题,以阐明我需要ES6模块在我的普通JS脚本的之前和之后运行。本质上,我需要将此简单的JS脚本集成到我的模块依赖图中。

EDIT2:我错了,延迟解决方案有效。请参见下面的@Aviad或我自己的答案

2 个答案:

答案 0 :(得分:1)

我认为这里的一个好习惯是为此创建某种下载管理器(例如,通过使用webpack块加载/动态导入)

另一种选择是使用defer属性。 请注意,defer表示脚本按遇到的顺序运行 ,因此,如果调用顺序为parser.js,则可以假定在调用interpreter.js时已加载sklearn正确。

链接:

答案 1 :(得分:0)

因此,我使用@Aviad的solution(如上所述)解决了该问题,并将defer添加到了我的所有脚本中,例如:

    <script src="lexer.js" type="module" defer></script>
    <script src="parser.js" defer></script>
    <script src="interpreter.js" type="module" defer></script>

,它开始以正确的顺序加载它们。整齐!尽管我认为需要注意的重要一点是,我还没有找到ES6模块加载顺序的实际规范,所以似乎无法保证加载顺序(除了其中一个模块依赖于另一个模块的情况外,它会先加载依赖项)。因此,尽管defer技巧目前可以使用,但我认为将来有可能打破它。

我还想提到,事实证明我的XMLHttpRequest同步脚本加载实际上正在工作,而我刚遇到了一些范围界定问题。我必须从eval的范围中调用window,因为通常parser.js是作为HTML中的<script>标记加载的,因此它希望范围为{{ 1}},所以我需要window来模拟,就像这样:

eval()

所以我想我有一个备用,如果我需要的话。我还考虑手动将// load parser script synchronously var req = new XMLHttpRequest(); req.open('GET', 'parser.js', false); req.send(null); eval.call(window, req.responseText); 转换为ES6模块,但这免除了我每次重新生成它时都要进行转换的麻烦。感谢@Aviad为您提供解决方案!