Membuat dan menjalankan JavaScript

Aplikasi Blockly sering menghasilkan JavaScript sebagai bahasa outputnya, biasanya untuk dijalankan dalam halaman web (mungkin sama, atau WebView yang disematkan). Seperti generator lainnya, langkah pertama adalah menyertakan generator JavaScript.

import {javascriptGenerator} from 'blockly/javascript';

Untuk membuat JavaScript dari ruang kerja, panggil:

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

Kode yang dihasilkan dapat dieksekusi langsung di halaman web tujuan:

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

Pada dasarnya, cuplikan di atas hanya menghasilkan kode dan mengevaluasinya. Namun, ada beberapa penyempurnaan. Salah satu penyempurnaannya adalah bahwa evaluasi di-wrap dalam try/catch sehingga error runtime apa pun dapat terlihat, bukan gagal tanpa pemberitahuan. Penyempurnaan lainnya adalah code ditambahkan ke daftar kata yang dicadangkan sehingga jika kode pengguna berisi variabel dengan nama tersebut, variabel akan otomatis diganti namanya, bukan bertabrakan. Semua variabel lokal harus dicadangkan dengan cara ini.

Blok Sorotan

Menandai blok yang sedang dieksekusi saat kode berjalan membantu pengguna memahami perilaku program mereka. Penyorotan dapat dilakukan di tingkat pernyataan dengan menetapkan STATEMENT_PREFIX sebelum membuat kode JavaScript:

javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');

Tentukan highlightBlock untuk menandai blok di ruang kerja.

function highlightBlock(id) {
  workspace.highlightBlock(id);
}

Hal ini akan menyebabkan pernyataan highlightBlock('123'); ditambahkan sebelum setiap pernyataan, dengan 123 adalah nomor seri blok yang akan ditandai.

Loop Tak Terbatas

Meskipun kode yang dihasilkan dijamin benar secara sintaksis setiap saat, kode tersebut mungkin berisi loop tak terbatas. Karena penyelesaian Masalah penghentian berada di luar cakupan Blockly (!), pendekatan terbaik untuk menangani kasus ini adalah mempertahankan penghitung dan menguranginya setiap kali iterasi dilakukan. Untuk melakukannya, cukup tetapkan javascriptGenerator.INFINITE_LOOP_TRAP ke cuplikan kode yang akan dimasukkan ke setiap loop dan setiap fungsi. Berikut contohnya:

window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);

Contoh

Berikut demo langsung tentang membuat dan mengeksekusi JavaScript.

JS-Interpreter

Jika Anda ingin menjalankan blok pengguna dengan benar, project JS-Interpreter adalah solusinya. Project ini terpisah dari Blockly, tetapi ditulis khusus untuk Blockly.

  • Jalankan kode dengan kecepatan apa pun.
  • Menjeda/melanjutkan/menjalankan langkah demi langkah eksekusi.
  • Menandai blok saat dieksekusi.
  • Benar-benar terisolasi dari JavaScript browser.

Menjalankan Interpreter

Pertama, download JS-Interpreter dari GitHub:

Kemudian, tambahkan ke halaman Anda:

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

Metode paling sederhana untuk memanggilnya adalah dengan membuat JavaScript, membuat interpreter, dan menjalankan kode:

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

Melangkah ke Interpreter

Untuk menjalankan kode lebih lambat, atau dengan cara yang lebih terkontrol, ganti panggilan ke run dengan loop yang bertahap (dalam hal ini satu langkah setiap 10 md):

function nextStep() {
  if (myInterpreter.step()) {
    setTimeout(nextStep, 10);
  }
}
nextStep();

Perhatikan bahwa setiap langkah bukanlah baris atau blok, melainkan unit semantik di JavaScript, yang mungkin sangat terperinci.

Menambahkan API

JS-Interpreter adalah sandbox yang sepenuhnya terisolasi dari browser. Blok yang melakukan tindakan dengan dunia luar memerlukan API yang ditambahkan ke interpreter. Untuk deskripsi lengkap, lihat dokumentasi JS-Interpreter. Namun, untuk memulai, berikut adalah API yang diperlukan untuk mendukung blok peringatan dan perintah:

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));
}

Kemudian, ubah inisialisasi interpreter Anda untuk meneruskan fungsi initApi:

var myInterpreter = new Interpreter(code, initApi);

Blok peringatan dan perintah adalah dua blok dalam set blok default yang memerlukan API kustom untuk interpreter.

Menghubungkan highlightBlock()

Saat berjalan di JS-Interpreter, highlightBlock() harus dieksekusi segera, di luar sandbox, saat pengguna menelusuri program. Untuk melakukannya, buat fungsi wrapper highlightBlock() untuk mengambil argumen fungsi, dan daftarkan sebagai fungsi native.

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));
}

Aplikasi yang lebih canggih mungkin ingin menjalankan langkah-langkah berulang kali tanpa menjeda hingga perintah sorotan tercapai, lalu menjeda. Strategi ini menyimulasikan eksekusi baris demi baris. Contoh di bawah menggunakan pendekatan ini.

Contoh JS-Interpreter

Berikut demo langsung penafsiran JavaScript langkah demi langkah. Selain itu, demo ini mencakup blok tunggu, contoh yang baik untuk digunakan pada perilaku asinkron lainnya (misalnya, ucapan atau audio, input pengguna).