Generowanie i uruchamianie JavaScriptu

Aplikacje Blockly często generują JavaScript jako język wyjściowy, zwykle działa na stronie internetowej (prawdopodobnie w tym samym lub w umieszczonym komponencie WebView). Tak jak w przypadku każdego generatora, pierwszym krokiem jest dołączenie generatora JavaScript.

import {javascriptGenerator} from 'blockly/javascript';

Aby wygenerować kod JavaScript z obszaru roboczego, wywołaj:

javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);

Uzyskany kod można wykonać bezpośrednio na stronie docelowej:

try {
  eval(code);
} catch (e) {
  alert(e);
}

Zasadniczo ten fragment kodu tylko generuje i ocenia. Pamiętaj jednak: wprowadziliśmy kilka doprecyzowań. Jedną z doprecyzowań jest to, że ocena jest objęta funkcją try/catch, aby były widoczne wszystkie błędy działania, a nie cicho. Kolejnym ulepszeniem jest dodanie słowa code do listy słów zarezerwowanych, dzięki czemu, jeśli kod użytkownika zawiera zmienną o tej nazwie, zostanie ona automatycznie przemianowana zamiast powodować konflikt. Wszystkie zmienne lokalne powinny być w ten sposób.

Bloki z najciekawszymi momentami

Wyróżnianie aktualnie uruchomionego bloku podczas uruchamiania kodu pomaga użytkownikom zrozumieć zachowanie w programie. Wyróżnianie można umieścić na poziomu instrukcji, ustawiając STATEMENT_PREFIX przed generując kod 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);
}

W efekcie przed każdą instrukcją zostanie dodana instrukcja highlightBlock('123');, gdzie 123 to numer seryjny bloku, który ma zostać wyróżniony.

Nieskończone pętle

Mimo że wygenerowany kod będzie w ogóle poprawny pod względem składni może zawierać nieskończone pętle. Od momentu rozwiązania Problem z blokowaniem jest poza zakresem W zakresie Blockly (!) najlepszym podejściem do takich przypadków jest utrzymuje licznik i zmniejsza go przy każdym wykonaniu iteracji. Aby to zrobić, ustaw javascriptGenerator.INFINITE_LOOP_TRAP jako kod który zostanie wstawiony do każdej pętli i 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 demo na żywo generowania i wykonywania kodu JavaScript.

Tłumacz języka JS

Jeśli poważnie podchodzisz do poprawnego uruchamiania blokad użytkownika, Projekt JS-Interpreter to słuszny wybór. Ten projekt jest czymś innym niż Blockly, ale został napisany z myślą o Blockly.

  • Uruchamiaj kod z dowolną szybkością.
  • Wstrzymaj/wznów/krok po kroku.
  • Zaznaczaj wykonywane bloki.
  • Jest całkowicie odizolowany od JavaScriptu w przeglądarce.

Uruchamianie tłumaczenia rozmowy

Najpierw pobierz JS-Interpreter z GitHuba:

Pobieranie pliku ZIP Pobierz TAR Ball Wyświetl w GitHubie

Następnie dodaj go do swojej strony:

<script src="acorn_interpreter.js"></script>

Najprostszą metodą jego wywołania jest wygenerowanie JavaScriptu, utworzenie interpreter i uruchom kod:

var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();

Postaw na tłumacza

Aby wykonywać kod wolniej lub w sposób bardziej kontrolowany, zastąp wywołaj run z pętlą wykonującą 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, jest jednostką semantyczną w JavaScript, który może być bardzo szczegółowy.

Dodaj interfejs API

Tłumacz JS to piaskownica, która jest całkowicie odizolowana od przeglądarki. Wszystkie bloki wykonujące działania w świecie zewnętrznym wymagają dodania interfejsu API tłumaczem. Pełny opis znajdziesz tutaj Dokumentacja JS-Interpreter Na początek przedstawiamy interfejs API potrzebny do obsługi bloków alertów i promptów:

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, by przekazywać 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 tłumaczenia rozmowy.

Łączę z dostawcą highlightBlock()

W przypadku użycia interpretera JS należy wykonać polecenie highlightBlock() natychmiast, poza piaskownicą, w miarę jak użytkownik przechodzi przez program. Do zrobienia utwórz funkcję opakowań highlightBlock(), aby przechwycić funkcję i zarejestruj go 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ą wielokrotnie wykonywać czynności bez wstrzymywania, aż do momentu, gdy dojdzie do polecenia wyróżnienia, a następnie wstrzymania. Ta strategia symuluje wykonanie linii po linii. Tę metodę zastosowano w przykładzie poniżej.

Przykład tłumaczenia rozmowy JS

Oto demo na żywo, które krok po kroku pokazuje interpretację kodu JavaScript. oraz ta wersja demonstracyjna zawiera blok oczekiwania, co jest dobrym przykładem do innych działań asynchronicznych. (np. mowa lub dźwięk, dane wejściowe użytkownika).