title: 应用程序集成 - 生成和运行Javascript
Generating and Running Javascript
原文:https://developers.google.com/blockly/guides/app-integration/running-javascript
阻止应用程序经常生成JavaScript作为其输出语言,通常在Web页面(可能是相同的,或嵌入式WebView)中运行。像任何生成器,第一步是包括javascript生成器。
对于Web Blockly,包括javascript_compressed.js
,紧接着blockly_compressed.js
:
WEB
<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
要从工作区生成JavaScript,请调用:
WEB
Blockly.JavaScript.addReservedWords('code');
var code = Blockly.JavaScript.workspaceToCode(workspace);
Blockly for Android生成JavaScript默认情况下,不应该需要配置。有关详细信息,请参阅使用自定义JavaScript生成器Using custom JavaScript Generators。
生成的代码可以在目标网页中执行
try {
eval(code);
} catch (e) {
alert(e);
}
基本上,上面的代码片段只是生成代码和evals它。然而,有几个细化。一个细化是eval包裹在一个try / catch,以便任何运行时错误是可见的,而不是安静地失败。另一个细化是将代码添加到保留字列表,以便如果用户的代码包含该名称的变量,它将被自动重命名,而不是冲突。任何局部变量都应该以这种方式保留。
突出显示块(仅限Web)
在同一页面中运行代码的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是要突出显示的块的序列号。
无限循环
虽然结果代码在任何时候都保证在语法上是正确的,但它可能包含无限循环。由于求解Halting问题Halting problem超出了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解释器项目是必须要走的路。这个项目与Blockly分开,但是专门为Blockly写的。
- 以任何速度执行代码
- 暂停/恢复/逐步执行。
- 突出显示块执行时。
- 完全隔离浏览器的JS。
这里是使用Blockly和JS Interpreter生成和执行JavaScript的现场演示a live demo。
运行解释器
首先,从GitHub下载JS解释器:
ZIP File
TAR Ball
GitHub
然后将其添加到您的网页:
<script src="acorn_interpreter.js"></script>
调用它的最简单的方法是生成JavaScript,创建解释器,并运行代码:
var code = Blockly.JavaScript.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
单步解释(Step the Interpreter)
为了更慢地或以更受控的方式执行代码,将调用替换为使用循环执行的调用(在这种情况下每10ms一步)
function nextStep() {
if (myInterpreter.step()) {
window.setTimeout(nextStep, 10);
}
}
nextStep();
注意,每个步骤不是一行或一个块,它是JavaScript中的语义单元,它可能是非常细粒度的。
添加API
JS解释器是一个与浏览器完全隔离的沙盒。任何对外界执行操作的块都需要向解释器添加API。有关完整说明,请参阅JS-Interpreter documentation文档。但首先,这里是需要支持警报和提示块的API:
function initApi(interpreter, scope) {
// Add an API function for the alert() block.
var wrapper = function(text) {
text = text ? text.toString() : '';
return interpreter.createPrimitive(alert(text));
};
interpreter.setProperty(scope, 'alert',
interpreter.createNativeFunction(wrapper));
// Add an API function for the prompt() block.
wrapper = function(text) {
text = text ? text.toString() : '';
return interpreter.createPrimitive(prompt(text));
};
interpreter.setProperty(scope, 'prompt',
interpreter.createNativeFunction(wrapper));
}
然后修改您的解释器初始化以传入initApi函数:
var myInterpreter = new Interpreter(code, initApi);
警告和提示块是缺省的块集中只有需要为解释器定制API的两个块。
正在连接highlightBlock()
当在JS解释器中运行时,在用户逐步浏览程序时,highlightBlock()应该立即在沙盒外执行。为此,创建一个包装器函数highlightBlock()来捕获函数参数,并将其注册为本机函数。
function initApi(interpreter, scope) {
// Add an API function for highlighting blocks.
var wrapper = function(id) {
id = id ? id.toString() : '';
return interpreter.createPrimitive(workspace.highlightBlock(id));
};
interpreter.setProperty(scope, 'highlightBlock',
interpreter.createNativeFunction(wrapper));
}
更复杂的应用程序可能希望重复执行步骤而不暂停,直到达到突出显示命令,然后暂停。此策略模拟逐行执行。下面的示例使用此方法。
JS解释器示例
这里是一步一步解释JavaScript的现场演示a live demo