Aplikacje blokujące często generują kod JavaScript jako język wyjściowy, które zwykle działają na stronie internetowej (prawdopodobnie taka sama lub w osadzonym komponencie WebView). Podobnie jak w przypadku każdego generatora, najpierw musisz dodać generator JavaScript.
import {javascriptGenerator} from 'blockly/javascript';
Aby wygenerować kod JavaScript z obszaru roboczego, wywołaj:
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
Powstały kod można wykonać bezpośrednio na docelowej stronie internetowej:
try {
eval(code);
} catch (e) {
alert(e);
}
Powyższy fragment kodu tylko generuje i ocenia kod. Jest jednak kilka udoskonaleń. Jednym z udoskonaleń jest zawarcie w ocenie wartości try
/catch
, dzięki czemu będą widoczne wszystkie błędy środowiska wykonawczego, a nie błąd powodujący. Innym ulepszeniem jest dodanie słowa code
do listy zarezerwowanych słów, dzięki czemu, jeśli kod użytkownika zawiera zmienną z tą nazwą, zmienia się ona automatycznie, a nie koliduje. Wszystkie zmienne lokalne
należy zachować w ten sposób.
Podświetlanie bloków
Wyróżnienie aktualnie wykonywanego bloku podczas uruchamiania kodu pomaga użytkownikom zrozumieć działanie programu. Wyróżnienie można wyróżnić na poziomie poszczególnych instrukcji, ustawiając STATEMENT_PREFIX
przed wygenerowaniem kodu JavaScript:
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
Określ highlightBlock
, aby oznaczyć bryłę w obszarze roboczym.
function highlightBlock(id) {
workspace.highlightBlock(id);
}
Spowoduje to dodanie instrukcji highlightBlock('123');
przed każdym wyrażeniem, gdzie 123
to numer seryjny bloku, który ma zostać wyróżniony.
Nieskończone pętle
Mimo że powstały kod zawsze ma poprawną składnię, może zawierać zapętlenie. Rozwiązanie problemu Halting wykracza poza zakres działania Blockly (!), dlatego najlepszym sposobem radzenia sobie z takimi przypadkami jest utrzymywanie licznika i zmniejszanie go przy każdym wykonaniu iteracji.
Aby to zrobić, ustaw w polu javascriptGenerator.INFINITE_LOOP_TRAP
fragment kodu, który będzie wstawiany w każdą pętlę i do każdej funkcji. Oto przykład:
window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);
Przykład
Oto prezentacja generowania i wykonywania kodu JavaScript na żywo.
Tłumacz języka JS
Jeśli zależy Ci na prawidłowym uruchamianiu blokad użytkowników, zalecamy skorzystanie z projektu JS-Interpreter. Ten projekt jest czymś innym niż Blockly, ale został napisany specjalnie dla Blockly.
- Uruchamiaj kod, kiedy chcesz.
- Wstrzymywanie/wznawianie/wykonywanie krok po kroku.
- Podświetlaj bloki w trakcie wykonywania.
- Całkowicie odizolowane od kodu JavaScript przeglądarki.
Uruchamianie tłumaczenia rozmowy
Najpierw pobierz z GitHuba narzędzie JS-Interpreter:
Następnie dodaj go do strony:
<script src="acorn_interpreter.js"></script>
Najprostszą metodą jej wywołania jest wygenerowanie kodu JavaScript, utworzenie interpretatora i uruchomienie kodu:
var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
Tłumacz na bieżąco
Aby wykonywać kod wolniej lub w bardziej kontrolowany sposób, zastąp wywołanie run
pętlą, która wykonuje te kroki (w tym przypadku co 10 ms):
function nextStep() {
if (myInterpreter.step()) {
setTimeout(nextStep, 10);
}
}
nextStep();
Pamiętaj, że każdy krok nie jest linią ani blokiem, a jednostką semantyczną w języku JavaScript, która może być bardzo szczegółowa.
Dodaj interfejs API
Język JS-Interpreter to piaskownica, która jest całkowicie odizolowana od przeglądarki. Wszystkie bloki, które wykonują działania w obrębie świata zewnętrznego, wymagają interfejsu API dodanego do interpretera. Pełny opis znajdziesz w dokumentacji mechanizmu JS-Interpreter. Na początek oto interfejs API potrzebny do obsługi bloków alertów i próśb:
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));
}
Następnie zmodyfikuj inicjowanie interpretera tak, aby przekazywało się do funkcji initApi:
var myInterpreter = new Interpreter(code, initApi);
Bloki alertów i promptów to jedyne 2 bloki w domyślnym zestawie bloków, które wymagają niestandardowego interfejsu API dla interpretera.
Łączę z dostawcą highlightBlock()
W przypadku uruchomienia w narzędziu JS-interpreter polecenie highlightBlock()
powinno zostać wykonane natychmiast, poza piaskownicą, w miarę jak użytkownik przechodzi przez program. W tym celu utwórz funkcję otoczenia highlightBlock()
, aby przechwycić argument funkcji, i zarejestruj ją jako funkcję natywną.
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));
}
Bardziej zaawansowane aplikacje mogą chcieć wielokrotnie wykonać kroki bez wstrzymania do momentu osiągnięcia polecenia podświetlania, a następnie wstrzymać działanie. Symuluje ona wykonywanie kodu w poszczególnych wierszach. Podejście to zastosowano w przykładzie poniżej.
Przykład mechanizmu JS-interpreter
Oto prezentacja na żywo, która pokazuje, jak krok po kroku interpretować kod JavaScript. Ta prezentacja zawiera blok oczekiwania, który jest dobrym przykładem na potrzeby innych działań asynchronicznych (np. mowy lub dźwięku, wprowadzania danych przez użytkownika).