การสร้างและเรียกใช้ JavaScript

แอปพลิเคชันแบบบล็อกมักสร้าง JavaScript เป็นภาษาเอาต์พุต โดยทั่วไปจะทำงานภายในหน้าเว็บ (อาจจะเหมือนกันหรือ WebView แบบฝัง) ขั้นตอนแรกคือใส่โปรแกรมสร้าง JavaScript เช่นเดียวกับโปรแกรมสร้างอื่นๆ

import {javascriptGenerator} from 'blockly/javascript';

หากต้องการสร้าง JavaScript จากพื้นที่ทำงาน ให้เรียก

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

โค้ดที่ได้นี้สามารถเรียกใช้งานได้ทันทีในหน้าเว็บปลายทาง:

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

โดยพื้นฐานแล้ว ข้อมูลโค้ดด้านบนเพียงแค่สร้างโค้ดและ 1 โค้ด อย่างไรก็ตาม มีการปรับเกณฑ์การค้นหาอีก 2-3 รายการ การปรับเกณฑ์การค้นหา 1 อย่างคือ Eval จะรวมอยู่ใน try/catch เพื่อให้มองเห็นข้อผิดพลาดรันไทม์ได้ แทนที่จะล้มเหลวแบบเงียบๆ การปรับเกณฑ์การค้นหาอีกอย่างคือ จะมีการเพิ่ม code ลงในรายการคำที่สงวนไว้ ดังนั้นหากโค้ดของผู้ใช้มีตัวแปรของชื่อนั้นจะเปลี่ยนชื่อโดยอัตโนมัติแทนการชนกัน ตัวแปรในเครื่องควรเก็บไว้ด้วยวิธีนี้

ไฮไลต์บล็อก

การไฮไลต์บล็อกที่ดำเนินการอยู่ในปัจจุบันในขณะที่โค้ดทำงานจะช่วยให้ผู้ใช้ เข้าใจพฤติกรรมของโปรแกรม การไฮไลต์อาจทำในระดับคำสั่งต่อคำสั่งได้โดยการตั้งค่า STATEMENT_PREFIX ก่อนที่จะสร้างโค้ด JavaScript ดังนี้

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

กําหนด highlightBlock เพื่อทําเครื่องหมายการบล็อกในพื้นที่ทำงาน

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

ซึ่งส่งผลให้มีการเพิ่มคำสั่ง highlightBlock('123'); ก่อนคำสั่งทั้งหมด โดย 123 เป็นหมายเลขซีเรียลของการบล็อกที่จะไฮไลต์

วนซ้ำไปเรื่อยๆ

แม้ว่าโค้ดที่ได้จะมีความถูกต้องทางไวยากรณ์ตลอดเวลา แต่อาจมีการวนซ้ำแบบไม่สิ้นสุด เนื่องจากการแก้ปัญหาปัญหาการหยุดทํางานอยู่นอกเหนือขอบเขตของ Blockly (!) วิธีที่ดีที่สุดในการจัดการกับกรณีเหล่านี้คือการรักษาการโต้แย้งและลดจำนวนทุกครั้งที่ดำเนินการ เพียงตั้งค่า javascriptGenerator.INFINITE_LOOP_TRAP เป็นข้อมูลโค้ดซึ่งจะแทรกลงในทุกลูปและทุกฟังก์ชัน ตัวอย่างเช่น

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

ตัวอย่าง

นี่คือการสาธิตการใช้งานจริง เกี่ยวกับการสร้างและการเรียกใช้ JavaScript

ล่าม JS

หากคุณจริงจังกับการดำเนินการบล็อกของผู้ใช้อย่างเหมาะสม ให้ไปโปรเจ็กต์ JS-Mediationer โปรเจ็กต์นี้ โปรเจ็กต์นี้แยกจาก Blockly แต่เขียนขึ้นสำหรับ Blockly โดยเฉพาะ

  • เรียกใช้โค้ดด้วยความเร็วที่ใดก็ได้
  • การดำเนินการหยุดชั่วคราว/ดำเนินการต่อ/แบบผ่าน
  • ไฮไลต์บล็อกขณะที่ดำเนินการ
  • แยกออกจาก JavaScript ของเบราว์เซอร์โดยสมบูรณ์

เรียกใช้ล่าม

ก่อนอื่น ให้ดาวน์โหลด JS- Translate จาก GitHub โดยทำดังนี้

ดาวน์โหลดไฟล์ ZIP ดาวน์โหลด TAR Ball ดูใน GitHub

จากนั้นให้เพิ่มลงในหน้าเว็บของคุณ โดยทำดังนี้

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

วิธีที่ง่ายที่สุดในการเรียก JavaScript คือการสร้าง JavaScript, สร้างล่าม และเรียกใช้โค้ด ดังนี้

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

ก้าวสู่การเป็นล่าม

หากต้องการให้โค้ดทำงานช้าลงหรือให้ควบคุมได้มากขึ้น ให้แทนที่การเรียกใช้ run ด้วยลูปที่ขั้นตอนดำเนินการ (ในกรณีนี้คือ 1 ก้าวทุกๆ 10 มิลลิวินาที)

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

โปรดทราบว่าแต่ละขั้นตอนไม่ใช่บรรทัดหรือบล็อก แต่เป็นหน่วยเชิงความหมายใน JavaScript ซึ่งอาจมีความละเอียดมาก

เพิ่ม API

JS-troubleshooterer เป็นแซนด์บ็อกซ์ที่แยกออกจากเบราว์เซอร์โดยสมบูรณ์ การบล็อกใดๆ ก็ตามที่โต้ตอบกับบุคคลภายนอกจำเป็นต้องเพิ่ม API ลงในอินเตอร์พรีเตอร์ ดูคำอธิบายทั้งหมดได้ในเอกสารประกอบ JS-ล่าม แต่เพื่อเป็นการเริ่มต้น นี่คือ API ที่จำเป็นในการรองรับการบล็อกการแจ้งเตือนและข้อความแจ้ง

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

จากนั้นแก้ไขการเริ่มต้นอินเทอร์พรีเตอร์ของคุณเพื่อให้ส่งผ่านในฟังก์ชัน initApi โดยทำดังนี้

var myInterpreter = new Interpreter(code, initApi);

การบล็อกการแจ้งเตือนและข้อความแจ้งเป็นบล็อกเพียง 2 บล็อกในชุดการบล็อกเริ่มต้นซึ่งต้องใช้ API ที่กำหนดเองสำหรับอินเตอร์พรีเตอร์

กำลังเชื่อมต่อกับ highlightBlock()

เมื่อเรียกใช้ใน JS-troubleshooterer ระบบควรดำเนินการ highlightBlock() ทันทีนอกแซนด์บ็อกซ์ เมื่อผู้ใช้ทำตามขั้นตอนในโปรแกรม โดยสร้างฟังก์ชัน Wrapper highlightBlock() เพื่อบันทึกอาร์กิวเมนต์ของฟังก์ชัน และลงทะเบียนเป็นฟังก์ชันเนทีฟ

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

แอปพลิเคชันที่ซับซ้อนมากขึ้นอาจต้องการทำตามขั้นตอนซ้ำๆ โดยไม่หยุดชั่วคราวจนกว่าจะเห็นคำสั่งไฮไลต์แล้วหยุดชั่วคราว กลยุทธ์นี้จำลองการดำเนินการทีละบรรทัด ตัวอย่างด้านล่างใช้วิธีการนี้

ตัวอย่างล่าม JS

ดูการสาธิตการใช้งานจริง เกี่ยวกับการตีความ JavaScript แบบทีละขั้นตอน และการสาธิตนี้ มีช่วงรอ ซึ่งเป็นตัวอย่างที่ดีในการใช้สำหรับลักษณะการทำงานอื่นๆ ที่ไม่พร้อมกัน (เช่น คำพูดหรือเสียง อินพุตของผู้ใช้)