แอปพลิเคชัน Blockly มักจะสร้าง JavaScript เป็นภาษาเอาต์พุต ซึ่งโดยทั่วไปจะทำงานภายในหน้าเว็บ (อาจเป็นหน้าเว็บเดียวกันหรือ WebView ที่ฝังอยู่) ขั้นตอนแรกคือใส่เครื่องมือสร้าง JavaScript เช่นเดียวกับเครื่องมือสร้างอื่นๆ
import {javascriptGenerator} from 'blockly/javascript';
หากต้องการสร้าง JavaScript จากพื้นที่ทํางาน ให้เรียกใช้
javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);
โค้ดที่ได้จะทํางานในหน้าเว็บปลายทางได้โดยตรง
try {
eval(code);
} catch (e) {
alert(e);
}
โดยพื้นฐานแล้วข้อมูลโค้ดด้านบนจะสร้างโค้ดและประเมิน อย่างไรก็ตาม ยังมีการปรับแต่งอีก 2-3 อย่าง การปรับปรุงอย่างหนึ่งคือ 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-Interpreter
หากคุณต้องการเรียกใช้บล็อกของผู้ใช้อย่างถูกต้อง โปรเจ็กต์ JS-Interpreter คือสิ่งที่คุณควรใช้ โปรเจ็กต์นี้แยกจาก Blockly แต่เขียนขึ้นเพื่อ Blockly โดยเฉพาะ
- เรียกใช้โค้ดด้วยความเร็วใดก็ได้
- หยุดชั่วคราว/เล่นต่อ/ดำเนินการทีละขั้นตอน
- ไฮไลต์บล็อกขณะที่ดำเนินการ
- แยกออกจาก JavaScript ของเบราว์เซอร์โดยสมบูรณ์
เรียกใช้อินเทอร์พรีเตอร์
ก่อนอื่น ให้ดาวน์โหลด JS-Interpreter จาก GitHub โดยทำดังนี้
จากนั้นเพิ่มลงในหน้าเว็บโดยทำดังนี้
<script src="acorn_interpreter.js"></script>
วิธีที่ง่ายที่สุดในการเรียกใช้คือการสร้าง 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-Interpreter คือแซนด์บ็อกซ์ที่แยกจากเบราว์เซอร์โดยสมบูรณ์ บล็อกที่ดำเนินการกับโลกภายนอกจะต้องเพิ่ม API ลงในโปรแกรมแปล ดูคำอธิบายทั้งหมดได้ในเอกสารประกอบเกี่ยวกับ JS-Interpreter แต่ก่อนอื่น มาดู 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-Interpreter ระบบควรเรียกใช้ 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-Interpreter
ต่อไปนี้คือการสาธิตแบบเรียลไทม์ของการตีความ JavaScript แบบทีละขั้นตอน และการสาธิตนี้มีบล็อกการรอ ซึ่งเป็นตัวอย่างที่ดีในการใช้กับลักษณะการทำงานแบบไม่พร้อมกันอื่นๆ (เช่น เสียงพูดหรือเสียง อินพุตของผู้ใช้)