إنشاء رمز JavaScript وتشغيله

تنتج تطبيقات 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);
}

بشكل أساسي، ينشئ المقتطف أعلاه الرمز ويقيّمه. مع ذلك، هناك بعض التحسينات. أحد التحسينات هو أنّ الدالة 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 هو الرقم التسلسلي للكتلة التي سيتم تمييزها.

Infinite Loops

على الرغم من أنّ الرمز الناتج يكون صحيحًا من الناحية النحوية في جميع الأوقات، قد يحتوي على حلقات لا نهائية. بما أنّ حل مشكلة التوقف يقع خارج نطاق 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 بحلقة تتضمّن خطوات (في هذه الحالة، خطوة واحدة كل 10 ملي ثانية):

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

يُرجى العِلم أنّ كل خطوة ليست سطرًا أو كتلة، بل هي وحدة دلالية في JavaScript، وقد تكون دقيقة للغاية.

إضافة واجهة برمجة تطبيقات

‫JS-Interpreter هي بيئة اختبار معزولة تمامًا عن المتصفّح. تتطلّب أيّ كتل برمجية تنفّذ إجراءات مع العالم الخارجي إضافة واجهة برمجة تطبيقات إلى المترجم. للحصول على وصف كامل، يُرجى الاطّلاع على مستندات JS-Interpreter. في ما يلي واجهة برمجة التطبيقات اللازمة لتوفير مربّعات التنبيهات والإشعارات:

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-Interpreter، يجب تنفيذ 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-Interpreter

إليك عرضًا توضيحيًا مباشرًا لطريقة تفسير JavaScript خطوة بخطوة. ويتضمّن هذا العرض التوضيحي كتلة انتظار، وهي مثال جيد يمكن استخدامه مع السلوكيات غير المتزامنة الأخرى (مثل الكلام أو الصوت أو إدخال المستخدم).