块应用通常会生成 JavaScript 作为其输出语言, 通常在网页(可能是同一网页,也可能是嵌入式 WebView)中运行。 与任何生成器一样,第一步是添加 JavaScript 生成器。
import {javascriptGenerator} from 'blockly/javascript';
要从工作区生成 JavaScript,请调用:
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
可以直接在目标网页中执行生成的代码:
try {
eval(code);
} catch (e) {
alert(e);
}
基本上,上述代码段只生成代码并对其进行评估。不过,
但仍有一些改进一种改进是将评估封装在
try
/catch
,以便显示所有运行时错误,而不是失败
安静。另一个优化是将 code
添加到预留
这样,如果用户的代码中包含该名称的变量,
而不会发生冲突所有局部变量都应以这种方式预留。
突出显示区块
在代码运行时突出显示当前正在执行的代码块有助于用户
了解其程序的行为。您可以先设置 STATEMENT_PREFIX
,然后再生成 JavaScript 代码,以便逐个语句地突出显示问题:
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
定义 highlightBlock
以在工作区中标记代码块。
function highlightBlock(id) {
workspace.highlightBlock(id);
}
这会导致将语句 highlightBlock('123');
添加到前面
每个语句,其中 123
是要接收的块的序列号
突出显示。
无限循环
尽管可以保证生成的代码的语法正确
那么它可能包含无限循环。自从解决
除了停止问题之外,
Blockly 的作用域 (!) 处理这些情况的最佳方法是
保留一个计数器并在每次执行迭代时递减该计数器。
为此,只需将 javascriptGenerator.INFINITE_LOOP_TRAP
设置为代码即可
该代码段将插入到每个循环和每个函数中。这里有一个
示例:
window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);
示例
以下是 现场演示 也就是生成和执行 JavaScript 的过程
JS 解释器
如果您确实想正确运行用户区块,那么 建议使用 JS-Interpreter 项目。 此项目独立于 Blockly,但专为 Blockly 而编写。
- 以任意速度执行代码。
- 暂停/恢复/逐步执行。
- 在块执行时突出显示它们。
- 与浏览器的 JavaScript 完全隔离。
运行解释器
首先,从 GitHub 下载 JS-Interpreter:
然后将其添加到您的页面中:
<script src="acorn_interpreter.js"></script>
调用该方法最简单的方法是:生成 JavaScript、创建 然后运行以下代码:
var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
跟随口译
若要减慢或以更受控的方式执行代码,请将
调用 run
,其中包含一个会递增的循环(在本例中,每 10 毫秒一步):
function nextStep() {
if (myInterpreter.step()) {
setTimeout(nextStep, 10);
}
}
nextStep();
请注意,每个步骤不是一行或一个块,而是 JavaScript(可能非常精细)。
添加 API
JS-Interpreter 是一个与浏览器完全隔离的沙盒。 任何与外部世界执行操作的块都需要向 翻译。有关完整说明,请参阅 JS-Interpreter 文档。 但首先,以下是支持提醒和提示块所需的 API:
function initApi(interpreter, globalObject) {
// Add an API function for the alert() block.
var wrapper = function(text) {
return alert(arguments.length ? text : '');
};
interpreter.setProperty(globalObject, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
wrapper = function(text) {
return prompt(text);
};
interpreter.setProperty(globalObject, 'prompt',
interpreter.createNativeFunction(wrapper));
}
然后,修改解释器初始化以传入 initApi 函数:
var myInterpreter = new Interpreter(code, initApi);
提醒屏蔽和提示屏蔽是默认屏蔽组中仅有的两个屏蔽设置 需要使用自定义 API 来解释器。
正在关联 highlightBlock()
在 JS-Interpreter 中运行时,应执行 highlightBlock()
当用户逐步执行程序时,在沙盒之外立即设置。待办事项
接下来,创建一个封装容器函数 highlightBlock()
来捕获该函数
参数,并将其注册为原生函数。
function initApi(interpreter, globalObject) {
// Add an API function for highlighting blocks.
var wrapper = function(id) {
return workspace.highlightBlock(id);
};
interpreter.setProperty(globalObject, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
更复杂的应用可能希望重复执行步骤, 暂停,直至达到突出显示命令,然后暂停。此策略会模拟 逐个执行。以下示例就是使用此方法。
JS 解释器示例
以下是实时演示,演示了如何分步解读 JavaScript。且 本演示 包含一个等待块,其他异步行为就是很好的示例。 (例如语音或音频、用户输入)。