5.2 生成并运行 Javascript
块状应用程序通常生成 JavaScript 作为其输出语言,通常在网页(可能是同一网页或嵌入式 WebView)中运行。 像任何生成器一样,第一步是导入 javascript 生成器。
对于 Web Blockly,请在 blockly_compressed.js 之后添加 javascript_compressed.js:
<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
要从工作空间生成 JavaScript 代码,请调用:
Blockly.JavaScript.addReservedWords('code');
var code = Blockly.JavaScript.workspaceToCode(workspace);
默认情况下,Blockly for Android 会生成 JavaScript,并且不需要配置。 有关更多详细信息,请参见使用自定义 JavaScript 生成器。
生成的代码可以直接在目标网页上执行:
try {
eval(code);
} catch (e) {
alert(e);
}
基本上,上面的代码片段只是生成代码并对其进行评估。 但是,有一些改进。 一种改进是,将评估结果包装在 try / catch 中,以便可以看到所有运行时错误,而不是悄无声息地失败。 另一个改进是,将代码添加到保留字列表中,这样,如果用户的代码包含该名称的变量,它将被自动重命名而不是冲突。 任何局部变量都应以这种方式保留。
突出显示块(仅 Web)highlightBlock
在同一页面中运行代码的 Web 应用程序通常会在代码运行时突出显示当前正在执行的块。 可以在生成 JavaScript 代码之前通过设置 STATEMENT_PREFIX 在逐条语句级别上完成此操作:
Blockly.JavaScript.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
Blockly.JavaScript.addReservedWords('highlightBlock');
定义 highlightBlock 以标记工作空间上的块。
function highlightBlock(id) {
workspace.highlightBlock(id);
}
这将导致语句 HighlightBlock('123'); 被添加到每个语句之前,其中 123 是要突出显示的块的序列号。
无限循环
尽管可以保证生成的代码在语法上始终正确,但是它可能包含无限循环。 由于解决暂停问题超出了 Blockly 的范围(!),处理这些情况的最佳方法是维护一个计数器,并在每次执行迭代时将其递减。 为此,只需将 Blockly.JavaScript.INFINITE_LOOP_TRAP 设置为代码片段,即可将其插入每个循环和每个函数中。 这是一个例子:
window.LoopTrap = 1000;
Blockly.JavaScript.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = Blockly.JavaScript.workspaceToCode(workspace);
JS 转换
如果您认真考虑正确运行用户块,那么可以使用 JS Interpreter 项目。 该项目与 Blockly 分开,但是专门为 Blockly 编写。
- 以任何速度执行代码。
- 暂停/继续/逐步执行。
- 在执行时突出显示块。
- 与浏览器的 JS 完全隔离。
这是使用 Blockly 和 JS Interpreter 生成和执行 JavaScript 的现场演示:https://blockly-demo.appspot.com/static/demos/generator/index.html。
运行
首先,从 GitHub 上下载 JS Interpreter:
然后添加到你的页面:
<script src="acorn_interpreter.js"></script>
调用它的最简单方法是生成 JavaScript,创建解释器并运行代码:
var code = Blockly.JavaScript.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
转换步骤
为了更慢地执行代码或以更可控的方式执行代码,请使用逐步循环(在这种情况下,每 10 毫秒执行一次)的循环替换调用以运行:
function nextStep() {
if (myInterpreter.step()) {
window.setTimeout(nextStep, 10);
}
}
nextStep();
请注意,每个步骤都不是一行或一个块,而是 JavaScript 中的一个语义单元,它的粒度可能非常细。
添加一个 API
JS Interpreter 是一个沙箱,与浏览器完全隔离。 任何对外界执行动作的块都需要将 API 添加到解释器中。 有关完整说明,请参见 JS-Interpreter 文档。 但是首先,这是支持警报和提示块所需的 API:
function initApi(interpreter, scope) {
// Add an API function for the alert() block.
var wrapper = function(text) {
return alert(arguments.length ? text : '');
};
interpreter.setProperty(scope, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
wrapper = function(text) {
return prompt(text);
};
interpreter.setProperty(scope, 'prompt',
interpreter.createNativeFunction(wrapper));
}
然后修改您的解释器初始化以传递 initApi 函数:
var myInterpreter = new Interpreter(code, initApi);
警报和提示块是默认块集中仅有两个块,它们需要解释器的自定义 API。
连接
在 JS Interpretter 中运行时,当用户逐步执行程序时,highlightBlock()应该立即在沙箱外部执行。 为此,创建一个包装器函数 highlightBlock()来捕获函数参数,并将其注册为本地函数。
function initApi(interpreter, scope) {
// Add an API function for highlighting blocks.
var wrapper = function(id) {
return workspace.highlightBlock(id);
};
interpreter.setProperty(scope, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
更复杂的应用程序可能希望不停地重复执行步骤,直到到达高亮命令,然后再暂停。 此策略模拟逐行执行。 下面的示例使用这种方法。
JS Interpreter 例子
这是逐步解释 JavaScript 的现场演示。 这个演示包括一个等待块,这是一个用于其他异步行为(例如,语音或音频,用户输入)的好例子。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论