Le applicazioni blockly spesso generano JavaScript come linguaggio di output. in genere per l'esecuzione all'interno di una pagina web (possibilmente la stessa o una libreria WebView incorporata). Come per ogni generatore, il primo passaggio consiste nell'includere il generatore JavaScript.
import {javascriptGenerator} from 'blockly/javascript';
Per generare JavaScript dall'area di lavoro, richiama:
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
Il codice risultante può essere eseguito direttamente nella pagina web di destinazione:
try {
eval(code);
} catch (e) {
alert(e);
}
Fondamentalmente, lo snippet riportato sopra genera semplicemente il codice e lo valuta. Tuttavia,
devi apportare alcune modifiche. Un perfezionamento è che la valutazione è racchiusa in
try
/catch
, in modo che gli eventuali errori di runtime siano visibili, anziché non avere esito positivo
in silenzio. Un altro perfezionamento è che viene aggiunto code
all'elenco di elementi prenotati
in modo che se il codice dell'utente contiene una variabile con questo nome
rinominata automaticamente anziché in conflitto. Eventuali variabili locali devono essere
in questo modo.
Evidenzia blocchi
Evidenziare il blocco attualmente in esecuzione durante l'esecuzione del codice aiuta gli utenti
il comportamento del loro programma. L'evidenziazione può essere eseguita su
a livello di dichiarazione per le dichiarazioni impostando STATEMENT_PREFIX
prima di
generando il codice JavaScript:
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
Definisci highlightBlock
per contrassegnare il blocco nello spazio di lavoro.
function highlightBlock(id) {
workspace.highlightBlock(id);
}
Ciò determina l'aggiunta dell'istruzione highlightBlock('123');
a prima
ogni istruzione, dove 123
è il numero di serie del blocco
in evidenza.
Loop infiniti
Sebbene sia garantito che il codice risultante sia sintatticamente corretto,
volte, potrebbe contenere loop infiniti. Dopo aver risolto
Il problema di blocco non si limita
L'ambito di Blockly (!) L'approccio migliore per affrontare questi casi è
mantenere un contatore e diminuirlo ogni volta che viene eseguita un'iterazione.
A questo scopo, imposta javascriptGenerator.INFINITE_LOOP_TRAP
su un codice
che verrà inserito in ogni loop e in ogni funzione. Ecco un
esempio:
window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);
Esempio
Ecco una demo dal vivo di generazione ed esecuzione di JavaScript.
Interprete di JS
Se vuoi davvero eseguire correttamente i blocchi dell'utente, Il progetto JS-Interpreter è la soluzione. Questo progetto è separato da Blockly, ma è stato scritto specificamente per Blockly.
- Esegui codice a qualsiasi velocità.
- Metti in pausa/riprendi/passa l'esecuzione.
- Evidenzia i blocchi mentre vengono eseguiti.
- Completamente isolato dal codice JavaScript del browser.
Esegui la modalità Interprete
Innanzitutto, scarica JS-Interpreter da GitHub:
Quindi aggiungilo alla tua pagina:
<script src="acorn_interpreter.js"></script>
Il metodo più semplice per richiamarlo è generare il codice JavaScript, creare l'interprete ed eseguire il codice:
var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();
Eseguire il passaggio dell'interprete
Per eseguire il codice più lentamente o in modo più controllato, sostituisci la chiamata a run
con un ciclo che esegue dei passaggi (in questo caso un passaggio ogni 10 ms):
function nextStep() {
if (myInterpreter.step()) {
setTimeout(nextStep, 10);
}
}
nextStep();
Tieni presente che ogni passaggio non è una linea o un blocco, ma un'unità semantica JavaScript, che può essere molto granulare.
Aggiungi un'API
JS-Interpreter è una sandbox completamente isolata dal browser. È necessaria un'API per tutti i blocchi che eseguono azioni con il mondo esterno l'interprete. Per una descrizione completa, vedi Documentazione di JS-Interpreter. Tuttavia, per iniziare, l'API è necessaria per supportare i blocchi di avvisi e prompt:
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));
}
Quindi modifica l'inizializzazione dell'interprete in modo che passi la funzione initApi:
var myInterpreter = new Interpreter(code, initApi);
I blocchi di avviso e prompt sono gli unici due blocchi nell'insieme predefinito di blocchi che richiedono un'API personalizzata per l'interprete.
Collegamento di highlightBlock()
Quando viene eseguito in JS-Interpreter, highlightBlock()
deve essere eseguito immediatamente, al di fuori della sandbox, man mano che l'utente esegue il programma. Da fare
Crea quindi una funzione wrapper highlightBlock()
per acquisire la funzione
e registrarlo come funzione nativa.
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));
}
Le applicazioni più sofisticate potrebbero voler eseguire ripetutamente i passaggi senza pausa fino a raggiungere un comando di evidenziazione, quindi metti in pausa. Questa strategia simula riga per riga. Nell'esempio riportato di seguito viene utilizzato questo approccio.
Esempio di JS-Interpreter
Ecco una demo dal vivo di interpretare JavaScript passo dopo passo. Inoltre, questa demo include un blocco di attesa, un buon esempio da utilizzare per altri comportamenti asincroni (ad es. parlato o audio, input utente).