JavaScript जनरेट करना और चलाना

ब्लॉकली ऐप्लिकेशन अक्सर अपनी आउटपुट भाषा के तौर पर JavaScript जनरेट करते हैं. आम तौर पर, इन्हें किसी वेब पेज (शायद उसी तरह या एम्बेड किए गए वेबव्यू) में चलाया जाता है. किसी भी जनरेटर की तरह, सबसे पहला कदम है JavaScript जनरेटर को शामिल करना.

import {javascriptGenerator} from 'blockly/javascript';

फ़ाइल फ़ोल्डर से JavaScript जनरेट करने के लिए, इन्हें कॉल करें:

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

इससे मिलने वाला कोड, डेस्टिनेशन वेब पेज पर ही लागू किया जा सकता है:

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

बुनियादी तौर पर, ऊपर दिया गया स्निपेट सिर्फ़ कोड जनरेट करता है और उसे दिखाता है. हालांकि, यहां कुछ सुधार किए गए हैं. एक रिफ़ाइनमेंट यह है कि eval को try/catch में रैप कर दिया जाता है, ताकि रनटाइम की सभी गड़बड़ियां दिखाई दें और गड़बड़ी का पता ही न चले. एक और बेहतर यह है कि code को रिज़र्व किए गए शब्दों की सूची में जोड़ दिया जाता है. इससे, अगर उपयोगकर्ता के कोड में उस नाम का कोई वैरिएबल होता है, तो टकराने के बजाय उसका नाम अपने-आप बदल जाएगा. सभी लोकल वैरिएबल को इस तरह से रिज़र्व किया जाना चाहिए.

हाइलाइट ब्लॉक

कोड के चलने के तौर पर चल रहे मौजूदा ब्लॉक को हाइलाइट करने से, उपयोगकर्ताओं को अपने प्रोग्राम के व्यवहार को समझने में मदद मिलती है. JavaScript कोड जनरेट करने से पहले STATEMENT_PREFIX सेट करके, उसे हर स्टेटमेंट के हिसाब से हाइलाइट किया जा सकता है:

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-अनुवादक प्रोजेक्ट इसका सही तरीका है. यह प्रोजेक्ट, Blockly से अलग है, लेकिन इसे खास तौर पर Blockly के लिए लिखा गया था.

  • कोड को किसी भी रफ़्तार से चलाएं.
  • रोकें/फिर से शुरू करें/सिलसिलेवार चलाएं.
  • ब्लॉक के चलने के दौरान उन्हें हाइलाइट करें.
  • ब्राउज़र की JavaScript से पूरी तरह अलग.

अनुवादक चलाएं

सबसे पहले, GitHub से JS-अनुवादक डाउनलोड करें:

ZIP फ़ाइल डाउनलोड करें TAR Ball डाउनलोड करें GitHub पर देखें

फिर इसे अपने पेज पर जोड़ें:

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

इसे कॉल करने का सबसे आसान तरीका है JavaScript जनरेट करना, इंटरप्रेटर बनाना, और कोड चलाना:

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

अनुवादक को आगे बढ़ाना

कोड को धीरे या ज़्यादा कंट्रोल से चलाने के लिए, run को किए जाने वाले कॉल को लूप से बदलें. इस लूप में हर 10 मि॰से॰ के बाद एक चरण पूरा किया जाएगा:

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

ध्यान दें कि हर चरण कोई लाइन या ब्लॉक नहीं है. यह JavaScript में एक सिमैंटिक यूनिट है, जिसमें बहुत बारीकी से जानकारी दी जा सकती है.

एपीआई जोड़ें

JS-अनुवादक एक सैंडबॉक्स है, जो ब्राउज़र से पूरी तरह अलग होता है. बाहरी दुनिया के साथ कार्रवाइयां करने वाले किसी भी ब्लॉक के लिए, अनुवादक में एपीआई जोड़ना ज़रूरी होता है. पूरी जानकारी के लिए, JS-अनुवादक दस्तावेज़ देखें. सबसे पहले, यहां बताया गया एपीआई कि सूचना और प्रॉम्प्ट ब्लॉक के साथ काम करने के लिए यह एपीआई ज़रूरी है:

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

ब्लॉक के डिफ़ॉल्ट सेट में, अलर्ट और प्रॉम्प्ट ब्लॉक ही दो ब्लॉक हैं जिन्हें इंटरप्रेटर के लिए कस्टम एपीआई की ज़रूरत होती है.

highlightBlock() को कनेक्ट कर रहा है

JS-अनुवादक में चलाते समय, उपयोगकर्ता के प्रोग्राम में आगे बढ़ने पर, सैंडबॉक्स के बाहर highlightBlock() को तुरंत एक्ज़ीक्यूट किया जाना चाहिए. इसके लिए, फ़ंक्शन आर्ग्युमेंट को कैप्चर करने के लिए, रैपर फ़ंक्शन 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 को सिलसिलेवार तरीके से समझने का एक लाइव डेमो यहां दिया गया है. इस डेमो में, इंतज़ार करने का समय शामिल है. एसिंक्रोनस व्यवहार (उदाहरण के लिए, बातचीत या ऑडियो, उपयोगकर्ता इनपुट) के लिए इसका इस्तेमाल किया जा सकता है.