生成并运行 JavaScript

块应用通常会生成 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:

下载 ZIP 文件 下载 TAR 文件包 在 GitHub 上查看

然后将其添加到您的页面中:

<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。且 本演示 包含一个等待块,其他异步行为就是很好的示例。 (例如语音或音频、用户输入)。