Skip to content

آلة افتراضية (تنفيذ جافا سكريبت)

[مستقر: 2 - مستقر]

مستقر: 2 استقرار: 2 - مستقر

رمز المصدر: lib/vm.js

تتيح وحدة node:vm تجميع وتشغيل التعليمات البرمجية داخل سياقات آلة V8 الافتراضية.

وحدة node:vm ليست آلية أمان. لا تستخدمها لتشغيل التعليمات البرمجية غير الموثوق بها.

يمكن تجميع وتشغيل تعليمات برمجة جافا سكريبت على الفور أو تجميعها وحفظها وتشغيلها لاحقًا.

حالة استخدام شائعة هي تشغيل التعليمات البرمجية في سياق V8 مختلف. هذا يعني أن التعليمات البرمجية التي يتم استدعاؤها لها كائن عالمي مختلف عن التعليمات البرمجية التي تستدعيها.

يمكن للمرء توفير السياق عن طريق وضع السياق لكائن. تعامل التعليمات البرمجية التي يتم استدعاؤها أي خاصية في السياق مثل متغير عالمي. أي تغييرات تطرأ على المتغيرات العالمية بسبب التعليمات البرمجية التي يتم استدعاؤها تنعكس في كائن السياق.

js
const vm = require('node:vm')

const x = 1

const context = { x: 2 }
vm.createContext(context) // وضع السياق للكائن.

const code = 'x += 40; var y = 17;'
// `x` و `y` متغيرات عالمية في السياق.
// في البداية، x قيمتها 2 لأن هذه هي قيمة context.x.
vm.runInContext(code, context)

console.log(context.x) // 42
console.log(context.y) // 17

console.log(x) // 1; y غير معرف.

فئة: vm.Script

مضافة في: v0.3.1

تحتوي مثيلات فئة vm.Script على نصوص مُجمعة مسبقًا يمكن تنفيذها في سياقات محددة.

new vm.Script(code[, options])

[السجل]

الإصدارالتغييرات
v21.7.0، v20.12.0تمت إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0، v16.12.0تمت إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
v10.6.0أصبح produceCachedData مُهملاً لصالح script.createCachedData().
v5.7.0خيارات cachedData و produceCachedData مدعومة الآن.
v0.3.1مضافة في: v0.3.1
  • code <سلسلة> تعليمات برمجة جافا سكريبت المراد تجميعها.
  • options <كائن> | <سلسلة>
    • filename <سلسلة> يحدد اسم الملف المستخدم في تتبعات المكدس التي أنتجتها هذه النصوص. الافتراضي: 'evalmachine.<anonymous>'.
    • lineOffset <رقم> يحدد إزاحة رقم السطر المعروضة في تتبعات المكدس التي أنتجتها هذه النصوص. الافتراضي: 0.
    • columnOffset <رقم> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبعات المكدس التي أنتجتها هذه النصوص. الافتراضي: 0.
    • cachedData <عازل> | <مصفوفة من النوع> | <بيانات عرض> يوفر عازل أو مصفوفة من النوع، أو بيانات عرض اختياريًا مع بيانات ذاكرة التخزين المؤقتة للرمز من V8 للمصدر المقدم. عند تقديمه، سيتم تعيين قيمة cachedDataRejected إلى true أو false بناءً على قبول البيانات من قبل V8.
    • produceCachedData <قيمة منطقية> عندما تكون true ولا يوجد cachedData، سيحاول V8 إنتاج بيانات ذاكرة التخزين المؤقتة للرمز لـ code. عند النجاح، سيتم إنتاج عازل يحتوي على بيانات ذاكرة التخزين المؤقتة للرمز من V8 وتخزينه في خاصية cachedData لمثيل vm.Script المُرجع. سيتم تعيين قيمة cachedDataProduced إلى true أو false بناءً على ما إذا تم إنتاج بيانات ذاكرة التخزين المؤقتة للرمز بنجاح أم لا. هذا الخيار مهمل لصالح script.createCachedData(). الافتراضي: false.
    • importModuleDynamically <دالة> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات أثناء تقييم هذه النصوص عند استدعاء import(). هذا الخيار جزء من واجهة برمجة التطبيقات التجريبية للوحدات. لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات، راجع دعم import() الديناميكي في واجهات برمجة التطبيقات للتجميع.

إذا كانت options سلسلة، فإنها تحدد اسم الملف.

إنشاء كائن vm.Script جديد يُجمع code ولكنه لا يُشغله. يمكن تشغيل vm.Script المُجمع لاحقًا عدة مرات. code غير مرتبط بأي كائن عالمي؛ بل يتم ربطه قبل كل تشغيل، فقط لهذا التشغيل.

script.cachedDataRejected

مضاف في: v5.7.0

عندما يتم تزويد cachedData لإنشاء vm.Script، سيتم تعيين هذه القيمة إلى true أو false بناءً على قبول البيانات بواسطة V8. خلاف ذلك، تكون القيمة undefined.

script.createCachedData()

مضاف في: v10.6.0

يُنشئ ذاكرة تخزين مؤقتة للرمز والتي يمكن استخدامها مع خيار cachedData الخاص بمنشئ Script. يُرجع Buffer. يمكن استدعاء هذه الطريقة في أي وقت وعدد غير محدود من المرات.

لا تحتوي ذاكرة التخزين المؤقتة للرمز الخاصة بـ Script على أي حالات قابلة للملاحظة في جافا سكريبت. من الآمن حفظ ذاكرة التخزين المؤقتة للرمز جنبًا إلى جنب مع مصدر البرنامج النصي واستخدامها لإنشاء مثيلات جديدة من Script عدة مرات.

يمكن تمييز الدوال في مصدر Script على أنها مُجمّعة بشكل كسول، ولا يتم تجميعها عند إنشاء Script. سيتم تجميع هذه الدوال عند استدعائها لأول مرة. تقوم ذاكرة التخزين المؤقتة للرمز بترتيب البيانات الوصفية التي يعرفها V8 حاليًا حول Script والتي يمكن استخدامها لتسريع عمليات التجميع المستقبلية.

js
const script = new vm.Script(`
function add(a, b) {
  return a + b;
}

const x = add(1, 2);
`)

const cacheWithoutAdd = script.createCachedData()
// في `cacheWithoutAdd` ، يتم تمييز الدالة `add()` للتجميع الكامل عند الاستدعاء.

script.runInThisContext()

const cacheWithAdd = script.createCachedData()
// `cacheWithAdd` يحتوي على الدالة `add()` المُجمّعة بالكامل.

script.runInContext(contextifiedObject[, options])

[History]

الإصدارالتغييرات
v6.3.0خيار breakOnSigint مدعوم الآن.
v0.3.1مضاف في: v0.3.1
  • contextifiedObject <Object> كائن مُحدد السياق كما هو مُرجع بواسطة طريقة vm.createContext().

  • options <Object>

    • displayErrors <boolean> عندما يكون true، إذا حدث خطأ Error أثناء تجميع code، فسيتم إرفاق سطر التعليمات البرمجية الذي تسبب في الخطأ بمسار التعقب. الافتراضي: true.
    • timeout <integer> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم طرح خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.
    • breakOnSigint <boolean> إذا كان true، فإن استقبال SIGINT (+) سيُنهي التنفيذ ويطرح خطأ Error. يتم تعطيل مُعالجات الأحداث الحالية التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، ولكنها تستمر في العمل بعد ذلك. الافتراضي: false.
  • القيمة المُرجعه: <any> نتيجة آخر بيان تم تنفيذه في البرنامج النصي.

يقوم بتشغيل التعليمات البرمجية المُجمّعة الموجودة في كائن vm.Script ضمن contextifiedObject المُعطى ويُرجع النتيجة. لا يمكن للتعليمات البرمجية قيد التشغيل الوصول إلى نطاق محلي.

يوضح المثال التالي تجميع التعليمات البرمجية التي تزيد من متغير عام، وتعيين قيمة متغير عام آخر، ثم تنفيذ التعليمات البرمجية عدة مرات. توجد المتغيرات العامة في كائن context.

js
const vm = require('node:vm')

const context = {
  animal: 'cat',
  count: 2,
}

const script = new vm.Script('count += 1; name = "kitty";')

vm.createContext(context)
for (let i = 0; i < 10; ++i) {
  script.runInContext(context)
}

console.log(context)
// يُطبع: { animal: 'cat', count: 12, name: 'kitty' }

سيؤدي استخدام خيارات timeout أو breakOnSigint إلى بدء حلقات أحداث جديدة وخيوط متوافقة، والتي لها عبء أداء غير صفري.

script.runInNewContext([contextObject[, options]])

[السجل]

الإصدارالتغييرات
v22.8.0, v20.18.0الآن، تقبل وسيطة contextObject قيمة vm.constants.DONT_CONTEXTIFY.
v14.6.0أصبح خيار microtaskMode مدعومًا الآن.
v10.0.0أصبح خيار contextCodeGeneration مدعومًا الآن.
v6.3.0أصبح خيار breakOnSigint مدعومًا الآن.
v0.3.1تمت الإضافة في: v0.3.1
  • contextObject <كائن> | <vm.constants.DONT_CONTEXTIFY> | <غير معرف> إما vm.constants.DONT_CONTEXTIFY أو كائن سيتم إضفاء سياق عليه. إذا كانت القيمة غير معرفة, فسيتم إنشاء كائن فارغ مُضْفَى سياقه من أجل التوافق مع الإصدارات السابقة.

  • options <كائن>

    • displayErrors <قيمة منطقية> عندما تكون صحيحًا, إذا حدث خطأ Error أثناء تجميع الرمز code, فسيتم إرفاق سطر الرمز الذي تسبب في الخطأ بمسار التعقب. الافتراضي: صحيح.

    • timeout <عدد صحيح> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم إرسال خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.

    • breakOnSigint <قيمة منطقية> إذا كانت صحيحًا, فإن استقبال SIGINT (+) سيؤدي إلى إنهاء التنفيذ وإرسال خطأ Error. سيتم تعطيل مُعالجات الأحداث الموجودة التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، لكنها ستستمر في العمل بعد ذلك. الافتراضي: خطأ.

    • contextName <سلسلة> اسم يُقرأ بسهولة للإنسان للسياق الذي تم إنشاؤه حديثًا. الافتراضي: 'VM Context i', حيث i هو مؤشر رقمي تصاعدي للسياق الذي تم إنشاؤه.

    • contextOrigin <سلسلة> المُنْشَأ المقابل للسياق الذي تم إنشاؤه حديثًا لأغراض العرض. يجب أن يكون المُنْشَأ مُنسقًا مثل عنوان URL، ولكن مع المخطط والمضيف والمنفذ فقط (إذا لزم الأمر)، مثل قيمة خاصية url.origin لكائن URL. والأهم من ذلك، يجب أن يُغفل هذا السلسلة الشرطة المائلة العكسية، لأنها تشير إلى مسار. الافتراضي: ''.

    • contextCodeGeneration <كائن>

    • strings <قيمة منطقية> إذا تم تعيينه على خطأ، فإن أي مكالمات لـ eval أو منشئي الدوال (Function, GeneratorFunction, إلخ) ستُرسل خطأ EvalError. الافتراضي: صحيح.

    • wasm <قيمة منطقية> إذا تم تعيينه على خطأ، فإن أي محاولة لتجميع وحدة WebAssembly ستُرسل خطأ WebAssembly.CompileError. الافتراضي: صحيح.

    • microtaskMode <سلسلة> إذا تم تعيينه على afterEvaluate, فسيتم تشغيل المهام الدقيقة (المهام المجدولة من خلال Promise و async function) فورًا بعد تشغيل البرنامج النصي. وهي مُدرجة في نطاقات timeout و breakOnSigint في هذه الحالة.

  • القيمة المُرجعة: <أي قيمة> نتيجة آخر بيان تم تنفيذه في البرنامج النصي.

هذه الطريقة اختصار لـ script.runInContext(vm.createContext(options), options). إنها تقوم بأشياء متعددة في وقت واحد:

يوضح المثال التالي تجميع الرمز الذي يُعيّن متغيرًا عامًا، ثم ينفذ الرمز عدة مرات في سياقات مختلفة. يتم تعيين المتغيرات العامة على كل سياق فردي واحتوائها داخله.

js
const vm = require('node:vm')

const script = new vm.Script('globalVar = "set"')

const contexts = [{}, {}, {}]
contexts.forEach(context => {
  script.runInNewContext(context)
})

console.log(contexts)
// يُطبع: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]

// سيؤدي هذا إلى إرسال خطأ إذا تم إنشاء السياق من كائن مُضْفَى سياقه.
// يسمح `vm.constants.DONT_CONTEXTIFY` بإنشاء سياقات باستخدام كائنات عامة عادية يمكن تجميدها.
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;')
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY)

script.runInThisContext([options])

[السجل]

الإصدارالتغييرات
v6.3.0أصبح خيار breakOnSigint مدعومًا الآن.
v0.3.1تمت الإضافة في: v0.3.1
  • options <Object>

    • displayErrors <boolean> عندما تكون true، إذا حدث خطأ Error أثناء تجميع code، فسيتم إرفاق سطر التعليمات البرمجية الذي تسبب في الخطأ بتتبع المكدس. الافتراضي: true.
    • timeout <integer> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم طرح خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.
    • breakOnSigint <boolean> إذا كانت true، فإن استقبال SIGINT (+) سيؤدي إلى إنهاء التنفيذ ورمي خطأ Error. يتم تعطيل المعالجات الموجودة للحدث التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، لكنها تستمر في العمل بعد ذلك. الافتراضي: false.
  • القيمة المُرجعة: <any> نتيجة آخر جملة تم تنفيذها في البرنامج النصي.

يقوم بتشغيل التعليمات البرمجية المُجمعة التي يحتويها vm.Script ضمن سياق كائن global الحالي. لا يمكن للتعليمات البرمجية قيد التشغيل الوصول إلى النطاق المحلي، ولكن يمكنها الوصول إلى كائن global الحالي.

يوضح المثال التالي تجميع التعليمات البرمجية التي تقوم بزيادة متغير global ثم تقوم بتنفيذ هذه التعليمات البرمجية عدة مرات:

js
const vm = require('node:vm')

global.globalVar = 0

const script = new vm.Script('globalVar += 1', { filename: 'myfile.vm' })

for (let i = 0; i < 1000; ++i) {
  script.runInThisContext()
}

console.log(globalVar)

// 1000

script.sourceMapURL

مضاف في: v19.1.0، v18.13.0

عندما يتم تجميع البرنامج النصي من مصدر يحتوي على تعليق سحري لخريطة المصدر، سيتم تعيين هذه الخاصية إلى عنوان URL لخريطة المصدر.

js
import vm from 'node:vm'

const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)

console.log(script.sourceMapURL)
// يطبع: sourcemap.json
js
const vm = require('node:vm')

const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)

console.log(script.sourceMapURL)
// يطبع: sourcemap.json

الصف: vm.Module

مضاف في: v13.0.0، v12.16.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1 - تجريبي

هذه الميزة متاحة فقط مع تمكين علم الأمر --experimental-vm-modules.

يوفر فئة vm.Module واجهة منخفضة المستوى لاستخدام وحدات ECMAScript في سياقات VM. وهي نظير لفئة vm.Script التي تعكس بشكل وثيق سجل الوحدة النمطية كما هو محدد في مواصفات ECMAScript.

على عكس vm.Script، فإن كل كائن vm.Module مرتبط بسياق من إنشائه. العمليات على كائنات vm.Module غير متزامنة بطبيعتها، على عكس الطبيعة المتزامنة لكائنات vm.Script. يمكن أن يساعد استخدام دوال "async" في معالجة كائنات vm.Module.

يتطلب استخدام كائن vm.Module ثلاث خطوات متميزة: إنشاء/تحليل، وربط، وتقييم. يتم توضيح هذه الخطوات الثلاث في المثال التالي.

يقع هذا التنفيذ على مستوى أدنى من محمل وحدة ECMAScript. لا توجد أيضًا طريقة للتفاعل مع Loader حتى الآن، على الرغم من أن الدعم مخطط له.

js
import vm from 'node:vm'

const contextifiedObject = vm.createContext({
  secret: 42,
  print: console.log,
})

// الخطوة 1
//
// إنشاء وحدة عن طريق إنشاء كائن `vm.SourceTextModule` جديد.  يقوم هذا بتحليل نص المصدر المقدم، ويرمي `SyntaxError` إذا حدث خطأ.  بشكل افتراضي، يتم إنشاء وحدة في السياق العلوي.  لكن هنا، نحدد `contextifiedObject` كسياق ينتمي إليه هذا الوحدة.
//
// هنا، نحاول الحصول على الصادرات الافتراضية من الوحدة "foo"، ووضعها في الربط المحلي "secret".

const bar = new vm.SourceTextModule(
  `
  import s from 'foo';
  s;
  print(s);
`,
  { context: contextifiedObject }
)

// الخطوة 2
//
// "ربط" التبعيات المستوردة لهذه الوحدة بها.
//
// يستقبل مُدعّم الربط المُقدم (الـ"linker") حُجتين: الوحدة الأصل (`bar` في هذه الحالة) والسلسلة التي تُمثّل مُحدّد الوحدة المستوردة.  من المتوقع أن يُعيد المُدعّم وحدة تتوافق مع المُحدّد المُقدم، مع متطلبات معينة موثقة في `module.link()`.
//
// إذا لم يبدأ الربط للوحدة المُعادة، فسيتم استدعاء مُدعّم الربط نفسه على الوحدة المُعادة.
//
// حتى الوحدات العلوية بدون تبعيات يجب ربطها صراحةً.  ولكن، لن يتم استدعاء مُدعّم الربط المُقدم أبدًا.
//
// تُعيد طريقة link() وعدًا سيتم حله عندما تُحل جميع الوعود التي تُعيدها وظيفة linker.
//
// ملاحظة: هذا مثال مُصطنع حيث تُنشئ وظيفة linker وحدة "foo" جديدة في كل مرة يتم استدعاؤها.  في نظام وحدة متكامل، من المحتمل استخدام ذاكرة تخزين مؤقت لتجنب تكرار الوحدات.

async function linker(specifier, referencingModule) {
  if (specifier === 'foo') {
    return new vm.SourceTextModule(
      `
      // يشير متغير "secret" إلى المتغير العام الذي أضفناه إلى
      // "contextifiedObject" عند إنشاء السياق.
      export default secret;
    `,
      { context: referencingModule.context }
    )

    // سيُعمل استخدام `contextifiedObject` بدلاً من `referencingModule.context`
    // هنا أيضًا.
  }
  throw new Error(`غير قادر على حل التبعية: ${specifier}`)
}
await bar.link(linker)

// الخطوة 3
//
// تقييم الوحدة.  تُعيد طريقة evaluate() وعدًا سيتم حله بعد انتهاء تقييم الوحدة.

// يطبع 42.
await bar.evaluate()
js
const vm = require('node:vm')

const contextifiedObject = vm.createContext({
  secret: 42,
  print: console.log,
})

;(async () => {
  // الخطوة 1
  //
  // إنشاء وحدة عن طريق إنشاء كائن `vm.SourceTextModule` جديد.  يقوم هذا بتحليل نص المصدر المقدم، ويرمي `SyntaxError` إذا حدث خطأ.  بشكل افتراضي، يتم إنشاء وحدة في السياق العلوي.  لكن هنا، نحدد `contextifiedObject` كسياق ينتمي إليه هذا الوحدة.
  //
  // هنا، نحاول الحصول على الصادرات الافتراضية من الوحدة "foo"، ووضعها في الربط المحلي "secret".

  const bar = new vm.SourceTextModule(
    `
    import s from 'foo';
    s;
    print(s);
  `,
    { context: contextifiedObject }
  )

  // الخطوة 2
  //
  // "ربط" التبعيات المستوردة لهذه الوحدة بها.
  //
  // يستقبل مُدعّم الربط المُقدم (الـ"linker") حُجتين: الوحدة الأصل (`bar` في هذه الحالة) والسلسلة التي تُمثّل مُحدّد الوحدة المستوردة.  من المتوقع أن يُعيد المُدعّم وحدة تتوافق مع المُحدّد المُقدم، مع متطلبات معينة موثقة في `module.link()`.
  //
  // إذا لم يبدأ الربط للوحدة المُعادة، فسيتم استدعاء مُدعّم الربط نفسه على الوحدة المُعادة.
  //
  // حتى الوحدات العلوية بدون تبعيات يجب ربطها صراحةً.  ولكن، لن يتم استدعاء مُدعّم الربط المُقدم أبدًا.
  //
  // تُعيد طريقة link() وعدًا سيتم حله عندما تُحل جميع الوعود التي تُعيدها وظيفة linker.
  //
  // ملاحظة: هذا مثال مُصطنع حيث تُنشئ وظيفة linker وحدة "foo" جديدة في كل مرة يتم استدعاؤها.  في نظام وحدة متكامل، من المحتمل استخدام ذاكرة تخزين مؤقت لتجنب تكرار الوحدات.

  async function linker(specifier, referencingModule) {
    if (specifier === 'foo') {
      return new vm.SourceTextModule(
        `
        // يشير متغير "secret" إلى المتغير العام الذي أضفناه إلى
        // "contextifiedObject" عند إنشاء السياق.
        export default secret;
      `,
        { context: referencingModule.context }
      )

      // سيُعمل استخدام `contextifiedObject` بدلاً من `referencingModule.context`
      // هنا أيضًا.
    }
    throw new Error(`غير قادر على حل التبعية: ${specifier}`)
  }
  await bar.link(linker)

  // الخطوة 3
  //
  // تقييم الوحدة.  تُعيد طريقة evaluate() وعدًا سيتم حله بعد انتهاء تقييم الوحدة.

  // يطبع 42.
  await bar.evaluate()
})()

module.dependencySpecifiers

محددات جميع تبعيات هذا المودول. المصفوفة المُرجعة مُجمّدة لمنع أي تغييرات عليها.

يتوافق مع حقل [[RequestedModules]] من سجلات المودول الدوري في مواصفات ECMAScript.

module.error

إذا كانت حالة module.status هي 'errored'، فإن هذه الخاصية تحتوي على الاستثناء الذي ألقاه المودول أثناء التقييم. إذا كانت الحالة أي شيء آخر، فإن الوصول إلى هذه الخاصية سيؤدي إلى إلقاء استثناء.

لا يمكن استخدام القيمة undefined للحالات التي لا يوجد فيها استثناء مُلقى بسبب الغموض المحتمل مع throw undefined;.

يتوافق مع حقل [[EvaluationError]] من سجلات المودول الدوري في مواصفات ECMAScript.

module.evaluate([options])

  • options <Object>

    • timeout <integer> يحدد عدد الميلي ثانية للتقييم قبل إنهاء التنفيذ. إذا تم مقاطعة التنفيذ، فسيتم إلقاء خطأ Error. يجب أن تكون هذه القيمة عدد صحيح موجب تمامًا.
    • breakOnSigint <boolean> إذا كانت true، فإن استقبال SIGINT (+) سيُنهي التنفيذ ويلقي خطأ Error. يتم تعطيل المُعالجات الموجودة للحدث التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، ولكنها تستمر في العمل بعد ذلك. الافتراضي: false.
  • الإرجاع: <Promise> يتم الوفاء به مع undefined عند النجاح.

تقييم المودول.

يجب استدعاء هذا بعد ربط المودول؛ وإلا فسيتم رفضه. يمكن استدعاءه أيضًا عندما يكون المودول قد تم تقييمه بالفعل، وفي هذه الحالة إما لن يفعل شيئًا إذا انتهى التقييم الأولي بنجاح (module.status هي 'evaluated') أو سيعيد إلقاء الاستثناء الذي نتج عنه التقييم الأولي (module.status هي 'errored').

لا يمكن استدعاء هذه الطريقة أثناء تقييم المودول (module.status هي 'evaluating').

يتوافق مع طريقة Evaluate() الملموسة من سجلات المودول الدوري في مواصفات ECMAScript.

module.identifier

معرّف الوحدة النمطية الحالية، كما هو مُعيّن في المُنشئ.

module.link(linker)

[السجل]

الإصدارالتغييرات
v21.1.0, v20.10.0, v18.19.0تم إعادة تسمية الخيار extra.assert إلى extra.attributes. لا يزال الاسم السابق مُتاحًا للتوافق مع الإصدارات القديمة.
  • linker <Function>

    • specifier <string> مُحدد الوحدة النمطية المطلوبة:

    • referencingModule <vm.Module> كائن Module الذي تم استدعاء دالة link() عليه.

    • extra <Object>

    • attributes <Object> البيانات من السمة: وفقًا لـ ECMA-262، من المتوقع أن تُحدث بيئات التشغيل خطأ إذا كانت هناك سمة غير مدعومة.

    • assert <Object> اسم مستعار لـ extra.attributes.

    • النتائج: <vm.Module> | <Promise>

  • النتائج: <Promise>

ربط تبعيات الوحدات النمطية. يجب استدعاء هذه الطريقة قبل التقييم، ولا يمكن استدعاءها إلا مرة واحدة لكل وحدة نمطية.

من المتوقع أن تُعيد الدالة كائن Module أو Promise الذي يتم حله في النهاية إلى كائن Module. يجب أن يلبي كائن Module المُعاد ما يلي:

  • يجب أن ينتمي إلى نفس سياق Module الأصل.
  • يجب ألا تكون حالته 'errored'.

إذا كانت حالة Module المُعاد هو 'unlinked', فسيتم استدعاء هذه الطريقة بشكل متكرر على Module المُعاد باستخدام دالة linker المُقدمة نفسها.

link() تُعيد Promise سيتم حله إما عند حل جميع حالات الربط إلى Module صالح، أو رفضه إذا ألقت دالة linker استثناءً أو أعادت Module غير صالح.

تتوافق دالة linker تقريبًا مع عملية HostResolveImportedModule المجردة المُعرّفة من قِبل التنفيذ في مواصفات ECMAScript، مع بعض الاختلافات الرئيسية:

التنفيذ الفعلي لـ HostResolveImportedModule المستخدم أثناء ربط الوحدات النمطية هو الذي يُعيد الوحدات المُرتبطة أثناء الربط. نظرًا لأن جميع الوحدات النمطية ستكون مرتبطة بالكامل في تلك المرحلة، فإن تنفيذ HostResolveImportedModule متزامن بالكامل وفقًا للمواصفات.

يتوافق مع حقل Link() concrete method من Cyclic Module Records في مواصفات ECMAScript.

module.namespace

كائن مساحة الاسم للوحدة النمطية. هذا متاح فقط بعد اكتمال الربط (module.link()).

يتوافق مع عملية GetModuleNamespace المجردة في مواصفات ECMAScript.

module.status

الحالة الحالية للوحدة النمطية. ستكون واحدة من:

  • 'unlinked': لم يتم استدعاء module.link() بعد.
  • 'linking': تم استدعاء module.link(), ولكن لم يتم حل جميع الوعود التي أعادتها دالة الرابط بعد.
  • 'linked': تم ربط الوحدة النمطية بنجاح، وجميع تبعياتها مرتبطة، ولكن لم يتم استدعاء module.evaluate() بعد.
  • 'evaluating': يجري تقييم الوحدة النمطية من خلال module.evaluate() على نفسها أو وحدة نمطية رئيسية.
  • 'evaluated': تم تقييم الوحدة النمطية بنجاح.
  • 'errored': تم تقييم الوحدة النمطية، ولكن تم طرح استثناء.

بخلاف 'errored', يتوافق سلسلة الحالة هذه مع حقل [[Status]] لسجل الوحدة النمطية الدورية Cyclic Module Record في المواصفات. يتوافق 'errored' مع 'evaluated' في المواصفات، ولكن مع تعيين [[EvaluationError]] لقيمة ليست undefined.

Class: vm.SourceTextModule

مضاف في: v9.6.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1 - تجريبي

هذه الميزة متاحة فقط مع تمكين علم الأمر --experimental-vm-modules.

توفر فئة vm.SourceTextModule سجل وحدة النص المصدر Source Text Module Record كما هو محدد في مواصفات ECMAScript.

new vm.SourceTextModule(code[, options])

[السجل]

الإصدارالتغييرات
v17.0.0, v16.12.0تمت إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
  • code <string> رمز وحدة JavaScript النمطية للتحليل

  • options

    • identifier <string> سلسلة مستخدمة في تتبعات المكدس. افتراضي: 'vm:module(i)' حيث i هو فهرس تصاعدي محدد للسياق.

    • cachedData <Buffer> | <TypedArray> | <DataView> يوفر Buffer أو TypedArray اختياريًا، أو DataView مع بيانات ذاكرة التخزين المؤقت للرمز الخاصة بـ V8 للمصدر المقدم. يجب أن يكون code هو نفسه الوحدة التي تم إنشاء cachedData منها.

    • context <Object> الكائن المُحدد السياق كما هو مُعاد من طريقة vm.createContext(), لترجمة وتقييم هذه Module فيها. إذا لم يتم تحديد سياق، فسيتم تقييم الوحدة النمطية في سياق التنفيذ الحالي.

    • lineOffset <integer> يحدد إزاحة رقم السطر المعروضة في تتبعات المكدس التي أنتجتها هذه Module. افتراضي: 0.

    • columnOffset <integer> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبعات المكدس التي أنتجتها هذه Module. افتراضي: 0.

    • initializeImportMeta <Function> يتم استدعاؤه أثناء تقييم هذه Module لتهيئة import.meta.

    • meta <import.meta>

    • module <vm.SourceTextModule>

    • importModuleDynamically <Function> يستخدم لتحديد كيفية تحميل الوحدات النمطية أثناء تقييم هذه الوحدة عند استدعاء import(). هذا الخيار جزء من واجهة برمجة تطبيقات الوحدات التجريبية. نحن لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات التفصيلية، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات الترجمة.

ينشئ مثيلًا جديدًا لـ SourceTextModule.

قد تسمح الخصائص المُعيّنة لكائن import.meta والتي تُعد كائنات للوحدة بالوصول إلى معلومات خارج السياق المُحدد. استخدم vm.runInContext() لإنشاء كائنات في سياق مُحدد.

js
import vm from 'node:vm'

const contextifiedObject = vm.createContext({ secret: 42 })

const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
  initializeImportMeta(meta) {
    // ملاحظة: يتم إنشاء هذا الكائن في السياق العلوي. على هذا النحو،
    // Object.getPrototypeOf(import.meta.prop) يشير إلى
    // Object.prototype في السياق العلوي بدلاً من ذلك الموجود في
    // الكائن المُحدد السياق.
    meta.prop = {}
  },
})
// بما أن الوحدة ليس لديها تبعيات، فلن يتم استدعاء دالة الرابط أبدًا.
await module.link(() => {})
await module.evaluate()

// الآن، سيكون Object.prototype.secret مساويًا لـ 42.
//
// لإصلاح هذه المشكلة، استبدل
//     meta.prop = {};
// أعلاه بـ
//     meta.prop = vm.runInContext('{}', contextifiedObject);
js
const vm = require('node:vm')
const contextifiedObject = vm.createContext({ secret: 42 })
;(async () => {
  const module = new vm.SourceTextModule('Object.getPrototypeOf(import.meta.prop).secret = secret;', {
    initializeImportMeta(meta) {
      // ملاحظة: يتم إنشاء هذا الكائن في السياق العلوي. على هذا النحو،
      // Object.getPrototypeOf(import.meta.prop) يشير إلى
      // Object.prototype في السياق العلوي بدلاً من ذلك الموجود في
      // الكائن المُحدد السياق.
      meta.prop = {}
    },
  })
  // بما أن الوحدة ليس لديها تبعيات، فلن يتم استدعاء دالة الرابط أبدًا.
  await module.link(() => {})
  await module.evaluate()
  // الآن، سيكون Object.prototype.secret مساويًا لـ 42.
  //
  // لإصلاح هذه المشكلة، استبدل
  //     meta.prop = {};
  // أعلاه بـ
  //     meta.prop = vm.runInContext('{}', contextifiedObject);
})()

sourceTextModule.createCachedData()

مضاف في: v13.7.0، v12.17.0

يُنشئ ذاكرة تخزين مؤقتة للشيفرة يمكن استخدامها مع خيار cachedData الخاص بمنشئ SourceTextModule. يُرجع مُخزن مؤقت Buffer. يمكن استدعاء هذه الطريقة أي عدد من المرات قبل تقييم الوحدة.

لا تحتوي ذاكرة التخزين المؤقتة للشيفرة الخاصة بـ SourceTextModule على أي حالات قابلة للملاحظة في JavaScript. من الآمن حفظ ذاكرة التخزين المؤقتة للشيفرة مع مصدر البرنامج النصي واستخدامها لإنشاء مثيلات جديدة من SourceTextModule عدة مرات.

يمكن تمييز الدوال الموجودة في مصدر SourceTextModule على أنها مُجمعة بشكل كسول، ولا يتم تجميعها عند إنشاء SourceTextModule. سيتم تجميع هذه الدوال عند استدعائها لأول مرة. تقوم ذاكرة التخزين المؤقتة للشيفرة بتسلسل البيانات الوصفية التي يعرفها V8 حاليًا حول SourceTextModule والتي يمكنه استخدامها لتسريع عمليات التجميع المستقبلية.

js
// إنشاء وحدة أولية
const module = new vm.SourceTextModule('const a = 1;')

// إنشاء بيانات مخزنة مؤقتًا من هذه الوحدة
const cachedData = module.createCachedData()

// إنشاء وحدة جديدة باستخدام البيانات المخزنة مؤقتًا. يجب أن يكون الرمز نفسه.
const module2 = new vm.SourceTextModule('const a = 1;', { cachedData })

الصنف: vm.SyntheticModule

مضاف في: v13.0.0، v12.16.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1 - تجريبي

هذه الميزة متوفرة فقط مع تمكين علم الأمر --experimental-vm-modules.

يوفر فئة vm.SyntheticModule سجل الوحدة الاصطناعية كما هو محدد في مواصفات WebIDL. الغرض من الوحدات الاصطناعية هو توفير واجهة عامة لعرض مصادر غير JavaScript على رسوم بيانية لوحدات ECMAScript.

js
const vm = require('node:vm')

const source = '{ "a": 1 }'
const module = new vm.SyntheticModule(['default'], function () {
  const obj = JSON.parse(source)
  this.setExport('default', obj)
})

// استخدام `module` في الربط...

new vm.SyntheticModule(exportNames, evaluateCallback[, options])

مضاف في: v13.0.0، v12.16.0

  • exportNames <string[]> مصفوفة من الأسماء التي سيتم تصديرها من الوحدة النمطية.
  • evaluateCallback <Function> يتم استدعاؤها عند تقييم الوحدة النمطية.
  • options
    • identifier <string> سلسلة تستخدم في تتبع المكدس. افتراضيًا: 'vm:module(i)' حيث i هو فهرس تصاعدي محدد بالسياق.
    • context <Object> الكائن المحدد بالسياق كما تم إرجاعه بواسطة طريقة vm.createContext()، لترجمة وتقييم هذه Module فيه.

يُنشئ مثيلًا جديدًا من SyntheticModule.

قد تسمح الكائنات المُعيّنة لصادرات هذا المثال للمستوردين للوحدة النمطية بالوصول إلى معلومات خارج السياق المحدد context. استخدم vm.runInContext() لإنشاء كائنات في سياق محدد.

syntheticModule.setExport(name, value)

مضاف في: v13.0.0، v12.16.0

  • name <string> اسم التصدير الذي سيتم تعيينه.
  • value <any> القيمة التي سيتم تعيين التصدير إليها.

تُستخدم هذه الطريقة بعد ربط الوحدة النمطية لتعيين قيم التصدير. إذا تم استدعاؤها قبل ربط الوحدة النمطية، فسيتم طرح خطأ ERR_VM_MODULE_STATUS.

js
import vm from 'node:vm'

const m = new vm.SyntheticModule(['x'], () => {
  m.setExport('x', 1)
})

await m.link(() => {})
await m.evaluate()

assert.strictEqual(m.namespace.x, 1)
js
const vm = require('node:vm')
;(async () => {
  const m = new vm.SyntheticModule(['x'], () => {
    m.setExport('x', 1)
  })
  await m.link(() => {})
  await m.evaluate()
  assert.strictEqual(m.namespace.x, 1)
})()

vm.compileFunction(code[, params[, options]])

[السجل]

الإصدارالتغييرات
v21.7.0, v20.12.0تمت إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v19.6.0, v18.15.0تتضمن قيمة الإرجاع الآن cachedDataRejected بنفس الدلالات الموجودة في إصدار vm.Script إذا تم تمرير خيار cachedData.
v17.0.0, v16.12.0تمت إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
v15.9.0تمت إضافة خيار importModuleDynamically مرة أخرى.
v14.3.0إزالة importModuleDynamically نظرًا لمشاكل التوافق.
v14.1.0, v13.14.0أصبح خيار importModuleDynamically مدعومًا الآن.
v10.10.0تمت الإضافة في: v10.10.0
  • code <string> نص الوظيفة المراد تجميعها.

  • params <string[]> مصفوفة من السلاسل تحتوي على جميع المعلمات للوظيفة.

  • options <Object>

    • filename <string> يحدد اسم الملف المستخدم في تتبع المكدس الذي أنتجته هذه البرنامج النصي. الافتراضي: ''.
    • lineOffset <number> يحدد إزاحة رقم السطر المعروضة في تتبع المكدس الذي أنتجته هذه البرنامج النصي. الافتراضي: 0.
    • columnOffset <number> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبع المكدس الذي أنتجته هذه البرنامج النصي. الافتراضي: 0.
    • cachedData <Buffer> | <TypedArray> | <DataView> يوفر Buffer أو TypedArray اختياريًا، أو DataView مع بيانات ذاكرة التخزين المؤقت للرمز الخاصة بـ V8 للمصدر المقدم. يجب إنتاج هذا بواسطة مكالمة سابقة إلى vm.compileFunction() باستخدام نفس code و params.
    • produceCachedData <boolean> يحدد ما إذا كان سيتم إنتاج بيانات ذاكرة تخزين مؤقت جديدة. الافتراضي: false.
    • parsingContext <Object> الكائن المُؤطر الذي يجب تجميع الوظيفة المذكورة فيه.
    • contextExtensions <Object[]> مصفوفة تحتوي على مجموعة من امتدادات السياق (الكائنات التي تغلف النطاق الحالي) المراد تطبيقها أثناء التجميع. الافتراضي: [].
  • importModuleDynamically <Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات أثناء تقييم هذه الوظيفة عند استدعاء import(). هذا الخيار جزء من واجهة برمجة تطبيقات الوحدات التجريبية. نحن لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات التفصيلية، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع.

  • قيمة الإرجاع: <Function>

يقوم بتجميع التعليمات البرمجية المعطاة في السياق المقدم (إذا لم يتم تقديم سياق، فسيتم استخدام السياق الحالي)، ويرجعها ملفوفة داخل وظيفة ذات params المحددة.

vm.constants

مضاف في: v21.7.0، v20.12.0

يرجع كائنًا يحتوي على ثوابت شائعة الاستخدام لعمليات VM.

vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER

مضاف في: v21.7.0، v20.12.0

[مستقر: 1 - تجريبي]

مستقر: 1 استقرار: 1.1 - تطوير نشط

ثابت يمكن استخدامه كخيار importModuleDynamically لـ vm.Script و vm.compileFunction() بحيث تستخدم Node.js محمل ESM الافتراضي من السياق الرئيسي لتحميل الوحدة المطلوبة.

للحصول على معلومات مفصلة، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع.

vm.createContext([contextObject[, options]])

[السجل]

الإصدارالتغييرات
v22.8.0، v20.18.0الآن تقبل وسيطة contextObject vm.constants.DONT_CONTEXTIFY.
v21.7.0، v20.12.0تمت إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v21.2.0، v20.11.0خيار importModuleDynamically مدعوم الآن.
v14.6.0خيار microtaskMode مدعوم الآن.
v10.0.0لم تعد الوسيطه الأولى يمكن أن تكون دالة.
v10.0.0خيار codeGeneration مدعوم الآن.
v0.3.1مضاف في: v0.3.1
  • contextObject <Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> إما vm.constants.DONT_CONTEXTIFY أو كائن سيتم وضعه في السياق. إذا كان undefined، فسيتم إنشاء كائن فارغ موضوع في السياق من أجل التوافق مع الإصدارات السابقة.

  • options <Object>

    • name <string> اسم سياق جديد تم إنشاؤه قابل للقراءة من قبل الإنسان. الافتراضي: 'VM Context i'، حيث i هو مؤشر رقمي تصاعدي للسياق الذي تم إنشاؤه.

    • origin <string> المصدر المقابل للسياق الذي تم إنشاؤه حديثًا لأغراض العرض. يجب تنسيق الأصل مثل عنوان URL، ولكن مع المخطط والمضيف والمنفذ فقط (إن لزم الأمر)، مثل قيمة خاصية url.origin لكائن URL. الأهم من ذلك، يجب أن يحذف هذا السلسلة الشرطة المائلة النهائية، لأنها تدل على المسار. الافتراضي: ''.

    • codeGeneration <Object>

    • strings <boolean> إذا تم تعيينه على false، فإن أي مكالمات لـ eval أو منشئي الدوال (Function، GeneratorFunction، إلخ) ستؤدي إلى طرح EvalError. الافتراضي: true.

    • wasm <boolean> إذا تم تعيينه على false، فإن أي محاولة لتجميع وحدة WebAssembly ستؤدي إلى طرح WebAssembly.CompileError. الافتراضي: true.

    • microtaskMode <string> إذا تم تعيينه على afterEvaluate، سيتم تشغيل المهام الدقيقة (المهام المجدولة من خلال Promise و async function) فورًا بعد تشغيل البرنامج النصي من خلال script.runInContext(). وهي مدرجة في نطاقات timeout و breakOnSigint في تلك الحالة.

    • importModuleDynamically <Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات عندما يتم استدعاء import() في هذا السياق بدون برنامج نصي أو وحدة مرجعية. هذا الخيار جزء من واجهة برمجة تطبيقات الوحدات التجريبية. نحن لا ننصح باستخدامه في بيئة إنتاج. للحصول على معلومات مفصلة، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع.

  • الإرجاع: <Object> كائن موضوع في السياق.

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

js
const vm = require('node:vm')

global.globalVar = 3

const context = { globalVar: 1 }
vm.createContext(context)

vm.runInContext('globalVar *= 2;', context)

console.log(context)
// يطبع: { globalVar: 2 }

console.log(global.globalVar)
// يطبع: 3

إذا تم حذف contextObject (أو تم تمريره صراحةً كـ undefined)، فسيتم إرجاع كائن جديد فارغ موضوع في السياق.

عندما يتم وضع الكائن العام في السياق في السياق الذي تم إنشاؤه حديثًا، فإنه يحتوي على بعض العيوب مقارنة بالكائنات العامة العادية. على سبيل المثال، لا يمكن تجميده. لإنشاء سياق بدون عيوب وضع الكائن في السياق، قم بتمرير vm.constants.DONT_CONTEXTIFY كوسيطة contextObject. راجع وثائق vm.constants.DONT_CONTEXTIFY للحصول على التفاصيل.

تُعد طريقة vm.createContext() مفيدة بشكل أساسي لإنشاء سياق واحد يمكن استخدامه لتشغيل العديد من البرامج النصية. على سبيل المثال، في حالة محاكاة متصفح ويب، يمكن استخدام هذه الطريقة لإنشاء سياق واحد يمثل الكائن العام للنافذة، ثم تشغيل جميع علامات \<script\> معًا داخل هذا السياق.

يتم جعل اسم السياق ومنشئه المُقدَّمين مرئيّين من خلال واجهة برمجة التطبيقات الخاصة بمفتش الأخطاء.

vm.isContext(object)

تم الإضافة في: v0.11.7

ترجع true إذا كان الكائن المُعطى object قد تم وضعه في سياق باستخدام vm.createContext()، أو إذا كان هو الكائن العام لسياق تم إنشاؤه باستخدام vm.constants.DONT_CONTEXTIFY.

vm.measureMemory([options])

تم الإضافة في: v13.10.0

[مستقر: 1 - تجريبي]

مستقر: 1 الثبات: 1 - تجريبي

قياس الذاكرة المعروفة لـ V8 والمستخدمة بواسطة جميع السياقات المعروفة لعزل V8 الحالي، أو السياق الرئيسي.

  • options <Object> اختياري.

    • mode <string> إما 'summary' أو 'detailed'. في وضع الملخص، سيتم إرجاع الذاكرة المقاسة للسياق الرئيسي فقط. في الوضع المفصل، سيتم إرجاع الذاكرة المقاسة لجميع السياقات المعروفة لعزل V8 الحالي. الافتراضي: 'summary'
    • execution <string> إما 'default' أو 'eager'. مع التنفيذ الافتراضي، لن يتم حل الوعد حتى بعد بدء عملية جمع القمامة المجدولة التالية، والتي قد تستغرق بعض الوقت (أو لا تكتمل أبدًا إذا خرج البرنامج قبل عملية جمع القمامة التالية). مع التنفيذ السريع، سيتم بدء عملية جمع القمامة على الفور لقياس الذاكرة. الافتراضي: 'default'
  • قيمة الإرجاع: <Promise> إذا تم قياس الذاكرة بنجاح، فسيتم حل الوعد بكائن يحتوي على معلومات حول استخدام الذاكرة. خلاف ذلك، سيتم رفضه بخطأ ERR_CONTEXT_NOT_INITIALIZED.

تنسيق الكائن الذي قد يحل به الوعد المُرجع هو خاص بمحرك V8 وقد يتغير من إصدار إلى آخر من V8.

النتيجة المُرجعه تختلف عن الإحصائيات المُرجعه بواسطة v8.getHeapSpaceStatistics() في أن vm.measureMemory() تقيس الذاكرة التي يمكن الوصول إليها بواسطة كل سياقات محددة V8 في مثيل المحرك الحالي لـ V8، بينما تقيس نتيجة v8.getHeapSpaceStatistics() الذاكرة التي يشغلها كل مساحة كومة في مثيل V8 الحالي.

js
const vm = require('node:vm')
// قياس الذاكرة المستخدمة بواسطة السياق الرئيسي.
vm.measureMemory({ mode: 'summary' })
  // هذا هو نفسه vm.measureMemory()
  .then(result => {
    // التنسيق الحالي هو:
    // {
    //   total: {
    //      jsMemoryEstimate: 2418479, jsMemoryRange: [ 2418479, 2745799 ]
    //    }
    // }
    console.log(result)
  })

const context = vm.createContext({ a: 1 })
vm.measureMemory({ mode: 'detailed', execution: 'eager' }).then(result => {
  // مرجع السياق هنا حتى لا يتم جمع القمامة
  // حتى يكتمل القياس.
  console.log(context.a)
  // {
  //   total: {
  //     jsMemoryEstimate: 2574732,
  //     jsMemoryRange: [ 2574732, 2904372 ]
  //   },
  //   current: {
  //     jsMemoryEstimate: 2438996,
  //     jsMemoryRange: [ 2438996, 2768636 ]
  //   },
  //   other: [
  //     {
  //       jsMemoryEstimate: 135736,
  //       jsMemoryRange: [ 135736, 465376 ]
  //     }
  //   ]
  // }
  console.log(result)
})

vm.runInContext(code, contextifiedObject[, options])

[السجل]

الإصدارالتغييرات
v21.7.0, v20.12.0تمت إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0, v16.12.0تمت إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
v6.3.0أصبح خيار breakOnSigint مدعومًا الآن.
v0.3.1تمت الإضافة في: v0.3.1
  • code <سلسلة> شفرة JavaScript التي سيتم تجميعها وتشغيلها.
  • contextifiedObject <كائن> الكائن المُعرّف بالسياق الذي سيتم استخدامه كـ global عند تجميع وتشغيل code.
  • options <كائن> | <سلسلة>
    • filename <سلسلة> يحدد اسم الملف المستخدم في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. افتراضيًا: 'evalmachine.\<anonymous\>'.
    • lineOffset <عدد> يحدد إزاحة رقم السطر المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. افتراضيًا: 0.
    • columnOffset <عدد> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. افتراضيًا: 0.
    • displayErrors <قيمة منطقية> عندما تكون true، إذا حدث خطأ Error أثناء تجميع code، فسيتم إرفاق سطر التعليمات البرمجية الذي تسبب في الخطأ بتتبع المكدس. افتراضيًا: true.
    • timeout <عدد صحيح> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم إرسال خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.
    • breakOnSigint <قيمة منطقية> إذا كانت true، فإن استقبال SIGINT (+) سيؤدي إلى إنهاء التنفيذ وإرسال خطأ Error. يتم تعطيل المعالجات الحالية للحدث التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، ولكنها تستمر في العمل بعد ذلك. افتراضيًا: false.
    • cachedData <عازل> | <TypedArray> | <DataView> يوفر Buffer أو TypedArray اختياريًا، أو DataView مع بيانات ذاكرة التخزين المؤقت للكود الخاصة بـ V8 للمصدر المُقدم.
    • importModuleDynamically <دالة> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات أثناء تقييم هذا البرنامج النصي عند استدعاء import (). هذا الخيار جزء من واجهة برمجة التطبيقات التجريبية للوحدات. نحن لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات التفصيلية، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع.

تقوم طريقة vm.runInContext() بتجميع code، وتشغيلها ضمن سياق contextifiedObject، ثم تقوم بإرجاع النتيجة. لا يمكن للكود قيد التشغيل الوصول إلى النطاق المحلي. يجب أن يكون كائن contextifiedObject قد تم تعريفه بالسياق مسبقًا باستخدام طريقة vm.createContext().

إذا كانت options سلسلة، فإنها تحدد اسم الملف.

يوضح المثال التالي تجميع وتنفيذ برامج نصية مختلفة باستخدام كائن واحد معرّف بالسياق:

js
const vm = require('node:vm')

const contextObject = { globalVar: 1 }
vm.createContext(contextObject)

for (let i = 0; i < 10; ++i) {
  vm.runInContext('globalVar *= 2;', contextObject)
}
console.log(contextObject)
// يطبع: { globalVar: 1024 }

vm.runInNewContext(code[, contextObject[, options]])

[History]

الإصدارالتغييرات
v22.8.0، v20.18.0الآن ، تقبل وسيطة contextObject قيمة vm.constants.DONT_CONTEXTIFY.
v21.7.0، v20.12.0تمت إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0، v16.12.0تمت إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
v14.6.0أصبح خيار microtaskMode مدعومًا الآن.
v10.0.0أصبح خيار contextCodeGeneration مدعومًا الآن.
v6.3.0أصبح خيار breakOnSigint مدعومًا الآن.
v0.3.1تمت الإضافة في: v0.3.1
  • code <string> شفرة JavaScript المراد تجميعها وتشغيلها.

  • contextObject <Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> إما vm.constants.DONT_CONTEXTIFY أو كائن سيتم وضعه في سياق. إذا كانت القيمة undefined، فسيتم إنشاء كائن فارغ تم وضعه في سياق من أجل التوافق مع الإصدارات السابقة.

  • options <Object> | <string>

    • filename <string> يحدد اسم الملف المستخدم في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 'evalmachine.\<anonymous\>'.

    • lineOffset <number> يحدد إزاحة رقم السطر المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 0.

    • columnOffset <number> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 0.

    • displayErrors <boolean> عندما تكون القيمة true، إذا حدث خطأ Error أثناء تجميع code، فسيتم إرفاق سطر التعليمات البرمجية الذي تسبب في الخطأ بتتبع المكدس. الافتراضي: true.

    • timeout <integer> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم طرح خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.

    • breakOnSigint <boolean> إذا كانت القيمة true، فإن تلقي SIGINT (+) سيؤدي إلى إنهاء التنفيذ وطرح خطأ Error. يتم تعطيل المعالجات الحالية للحدث التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، ولكنها تستمر في العمل بعد ذلك. الافتراضي: false.

    • contextName <string> اسم يمكن قراءته من قبل الإنسان للسياق الذي تم إنشاؤه حديثًا. الافتراضي: 'VM Context i'، حيث i هو مؤشر رقمي تصاعدي للسياق الذي تم إنشاؤه.

    • contextOrigin <string> Origin المقابل للسياق الذي تم إنشاؤه حديثًا لأغراض العرض. يجب أن يتم تنسيق الأصل مثل عنوان URL، ولكن مع المخطط والمضيف والمنفذ فقط (إذا لزم الأمر)، مثل قيمة خاصية url.origin لكائن URL. الأهم من ذلك، يجب أن يحذف هذا السلسلة الشرطة المائلة الأخيرة، حيث تشير إلى مسار. الافتراضي: ''.

    • contextCodeGeneration <Object>

    • strings <boolean> إذا تم تعيينها على false، فإن أي مكالمات إلى eval أو منشئي الدوال (Function، GeneratorFunction، إلخ) ستطرح خطأ EvalError. الافتراضي: true.

    • wasm <boolean> إذا تم تعيينها على false، فإن أي محاولة لتجميع وحدة WebAssembly ستطرح خطأ WebAssembly.CompileError. الافتراضي: true.

    • cachedData <Buffer> | <TypedArray> | <DataView> يوفر Buffer أو TypedArray اختياريًا، أو DataView مع بيانات ذاكرة التخزين المؤقت للرمز الخاصة بـ V8 للمصدر المقدم.

    • importModuleDynamically <Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات أثناء تقييم هذا البرنامج النصي عند استدعاء import (). هذا الخيار جزء من واجهة برمجة التطبيقات التجريبية للوحدات. لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات التفصيلية، راجع دعم import() الديناميكي في واجهات برمجة التطبيقات للتجميع.

    • microtaskMode <string> إذا تم تعيينها على afterEvaluate، فسيتم تشغيل المهام الدقيقة (المهام المجدولة عبر Promise و async functions) فورًا بعد تشغيل البرنامج النصي. وهي مدرجة في نطاقات timeout و breakOnSigint في تلك الحالة.

  • قيمة الإرجاع: <any> نتيجة آخر بيان تم تنفيذه في البرنامج النصي.

هذه الطريقة اختصار لـ (new vm.Script(code, options)).runInContext(vm.createContext(options), options). إذا كانت options سلسلة، فإنها تحدد اسم الملف.

إنها تقوم بأشياء كثيرة في وقت واحد:

يوضح المثال التالي تجميع وتنفيذ التعليمات البرمجية التي تزيد متغيرًا عالميًا وتعيين متغير جديد. توجد هذه المتغيرات العالمية في contextObject.

js
const vm = require('node:vm')

const contextObject = {
  animal: 'cat',
  count: 2,
}

vm.runInNewContext('count += 1; name = "kitty"', contextObject)
console.log(contextObject)
// يطبع: { animal: 'cat', count: 3, name: 'kitty' }

// هذا سيطرح خطأ إذا تم إنشاء السياق من كائن تم وضعه في سياق.
// يسمح `vm.constants.DONT_CONTEXTIFY` بإنشاء سياقات مع كائنات عالمية عادية يمكن تجميدها.
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY)

vm.runInThisContext(code[, options])

[السجل]

الإصدارالتغييرات
v21.7.0، v20.12.0تم إضافة دعم لـ vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER.
v17.0.0، v16.12.0تم إضافة دعم لسمات الاستيراد إلى معلمة importModuleDynamically.
v6.3.0أصبح خيار breakOnSigint مدعومًا الآن.
v0.3.1تمت الإضافة في: v0.3.1
  • code <سلسلة> شفرة جافاسكريبت المراد تجميعها وتشغيلها.

  • options <كائن> | <سلسلة>

    • filename <سلسلة> يحدد اسم الملف المستخدم في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 'evalmachine.\<anonymous\>'.
    • lineOffset <رقم> يحدد إزاحة رقم السطر المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 0.
    • columnOffset <رقم> يحدد إزاحة رقم عمود السطر الأول المعروضة في تتبعات المكدس التي أنتجتها هذه البرنامج النصي. الافتراضي: 0.
    • displayErrors <قيمة منطقية> عندما تكون true, إذا حدث خطأ Error أثناء تجميع code, يتم إرفاق سطر التعليمات البرمجية الذي تسبب في الخطأ بتتبع المكدس. الافتراضي: true.
    • timeout <عدد صحيح> يحدد عدد ميلي ثانية لتنفيذ code قبل إنهاء التنفيذ. إذا تم إنهاء التنفيذ، فسيتم طرح خطأ Error. يجب أن تكون هذه القيمة عددًا صحيحًا موجبًا تمامًا.
    • breakOnSigint <قيمة منطقية> إذا كانت true, فإن استلام SIGINT (+) سينهي التنفيذ ويرمي خطأ Error. يتم تعطيل المعالجات الحالية للحدث التي تم إرفاقها عبر process.on('SIGINT') أثناء تنفيذ البرنامج النصي، لكنها تستمر في العمل بعد ذلك. الافتراضي: false.
    • cachedData <عازل> | <TypedArray> | <DataView> يوفر Buffer أو TypedArray اختياريًا، أو DataView مع بيانات ذاكرة التخزين المؤقتة للرمز الخاصة بـ V8 للمصدر المقدم.
    • importModuleDynamically <دالة> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يستخدم لتحديد كيفية تحميل الوحدات أثناء تقييم هذا البرنامج النصي عند استدعاء import(). هذا الخيار جزء من واجهة برمجة تطبيقات الوحدات التجريبية. نحن لا نوصي باستخدامه في بيئة إنتاج. لمزيد من المعلومات التفصيلية، راجع دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع.
  • قيمة الإرجاع: <أي> نتيجة آخر بيان تم تنفيذه في البرنامج النصي.

يقوم vm.runInThisContext() بتجميع code، وتشغيله ضمن سياق global الحالي، وإرجاع النتيجة. لا يمكن للكود الذي يتم تشغيله الوصول إلى النطاق المحلي، ولكنه يمكنه الوصول إلى الكائن global الحالي.

إذا كانت options سلسلة، فإنها تحدد اسم الملف.

يوضح المثال التالي استخدام كل من vm.runInThisContext() ودالة جافاسكريبت eval() لتشغيل نفس الكود:

js
const vm = require('node:vm')
let localVar = 'initial value'

const vmResult = vm.runInThisContext('localVar = "vm";')
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`)
// يطبع: vmResult: 'vm', localVar: 'initial value'

const evalResult = eval('localVar = "eval";')
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`)
// يطبع: evalResult: 'eval', localVar: 'eval'

نظرًا لأن vm.runInThisContext() لا يمكنه الوصول إلى النطاق المحلي، فإن localVar لا يتغير. على النقيض من ذلك، فإن eval() يمكنه الوصول إلى النطاق المحلي، لذلك تتغير قيمة localVar. بهذه الطريقة، يكون vm.runInThisContext() مشابهًا جدًا لـ مكالمة eval() غير مباشرة، مثل (0,eval)('code').

مثال: تشغيل خادم HTTP داخل آلة افتراضية

عند استخدام أي من script.runInThisContext() أو vm.runInThisContext()، يتم تنفيذ الكود داخل سياق V8 العالمي الحالي. سيكون للكود الممرر إلى سياق VM هذا نطاق معزول خاص به.

من أجل تشغيل خادم ويب بسيط باستخدام وحدة node:http، يجب أن يقوم الكود الممرر إلى السياق إما باستدعاء require('node:http') بنفسه، أو أن يكون لديه مرجع لوحدة node:http الممررة إليه. على سبيل المثال:

js
'use strict'
const vm = require('node:vm')

const code = `
((require) => {
  const http = require('node:http');

  http.createServer((request, response) => {
    response.writeHead(200, { 'Content-Type': 'text/plain' });
    response.end('Hello World\\n');
  }).listen(8124);

  console.log('Server running at http://127.0.0.1:8124/');
})`

vm.runInThisContext(code)(require)

يشارك require() في الحالة أعلاه الحالة مع السياق الذي تم تمريره منه. قد يؤدي هذا إلى مخاطر عند تنفيذ كود غير موثوق به، مثل تغيير الكائنات في السياق بطرق غير مرغوب فيها.

ماذا يعني "تحديد سياق" كائن؟

يتم تشغيل كل جافا سكريبت التي يتم تنفيذها داخل Node.js ضمن نطاق "سياق". وفقًا لـ دليل مضمّن V8:

عندما يتم استدعاء طريقة vm.createContext() بكائن، سيتم استخدام وسيطة contextObject لمعالجة الكائن العالمي لمثال جديد من سياق V8 (إذا كانت contextObject هي undefined، فسيتم إنشاء كائن جديد من السياق الحالي قبل تعريفه في السياق). يوفر سياق V8 هذا الكود الذي يتم تشغيله باستخدام طرق وحدة node:vm ببيئة عالمية معزولة يمكنه العمل ضمنها. عملية إنشاء سياق V8 وربطه بـ contextObject في السياق الخارجي هي ما تشير إليه هذه الوثيقة باسم "تحديد سياق" الكائن.

سيؤدي تحديد السياق إلى بعض الخصائص الغريبة لقيمة globalThis في السياق. على سبيل المثال، لا يمكن تجميده، وهو ليس متساويًا في المرجع مع contextObject في السياق الخارجي.

js
const vm = require('node:vm')

// خيار `contextObject` غير معرف يجعل الكائن العالمي محددًا في السياق.
const context = vm.createContext()
console.log(vm.runInContext('globalThis', context) === context) // false
// لا يمكن تجميد كائن عالمي محدد في السياق.
try {
  vm.runInContext('Object.freeze(globalThis);', context)
} catch (e) {
  console.log(e) // TypeError: Cannot freeze
}
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)) // 1

لإنشاء سياق بكائن عالمي عادي والحصول على الوصول إلى وكيل عالمي في السياق الخارجي مع عدد أقل من الخصائص الغريبة، حدد vm.constants.DONT_CONTEXTIFY كوسيطة contextObject.

vm.constants.DONT_CONTEXTIFY

هذا الثابت، عند استخدامه كوسيط contextObject في واجهات برمجة التطبيقات الخاصة بـ vm، يُرشد Node.js إلى إنشاء سياق دون تغليف كائنه العالمي بكائن آخر بطريقة خاصة بـ Node.js. نتيجة لذلك، ستتصرف قيمة globalThis داخل السياق الجديد بشكل أقرب إلى قيمة عادية.

js
const vm = require('node:vm')

// استخدم vm.constants.DONT_CONTEXTIFY لتجميد الكائن العالمي.
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)
vm.runInContext('Object.freeze(globalThis);', context)
try {
  vm.runInContext('bar = 1; bar;', context)
} catch (e) {
  console.log(e) // Uncaught ReferenceError: bar is not defined
}

عندما يُستخدم vm.constants.DONT_CONTEXTIFY كوسيط contextObject لـ vm.createContext()، يكون الكائن المُرجع هو كائن شبيه بالوكيل للكائن العالمي في السياق المُنشأ حديثًا مع عدد أقل من العيوب الخاصة بـ Node.js. وهو مُساوي في المرجع لقيمة globalThis في السياق الجديد، ويمكن تعديله من خارج السياق، ويمكن استخدامه للوصول إلى المدمجات في السياق الجديد مباشرةً.

js
const vm = require('node:vm')

const context = vm.createContext(vm.constants.DONT_CONTEXTIFY)

// الكائن المُرجع مُساوي في المرجع لـ globalThis في السياق الجديد.
console.log(vm.runInContext('globalThis', context) === context) // true

// يمكن استخدامه للوصول إلى العناصر العالمية في السياق الجديد مباشرةً.
console.log(context.Array) // [Function: Array]
vm.runInContext('foo = 1;', context)
console.log(context.foo) // 1
context.bar = 1
console.log(vm.runInContext('bar;', context)) // 1

// يمكن تجميده، وهذا يؤثر على السياق الداخلي.
Object.freeze(context)
try {
  vm.runInContext('baz = 1; baz;', context)
} catch (e) {
  console.log(e) // Uncaught ReferenceError: baz is not defined
}

تفاعلات مهلة الوقت مع المهام غير المتزامنة والوعود

يمكن لـ Promise و async function جدولة المهام التي يقوم بإنشائها مُحرك JavaScript بشكل غير متزامن. بشكل افتراضي، يتم تشغيل هذه المهام بعد الانتهاء من تنفيذ جميع دوال JavaScript على المكدس الحالي. يسمح هذا بتجاوز وظائف خيارات timeout و breakOnSigint.

على سبيل المثال، يقوم الكود التالي الذي تم تنفيذه بواسطة vm.runInNewContext() مع مهلة زمنية قدرها 5 ملي ثانية بجدولة حلقة لا نهائية للتشغيل بعد حل وعد. لا يتم مقاطعة الحلقة المُجدولة أبدًا بواسطة المهلة الزمنية:

js
const vm = require('node:vm')

function loop() {
  console.log('entering loop')
  while (1) console.log(Date.now())
}

vm.runInNewContext('Promise.resolve().then(() => loop());', { loop, console }, { timeout: 5 })
// يتم طباعة هذا *قبل* 'entering loop' (!)
console.log('done executing')

يمكن معالجة هذا عن طريق تمرير microtaskMode: 'afterEvaluate' إلى الكود الذي يُنشئ Context:

js
const vm = require('node:vm')

function loop() {
  while (1) console.log(Date.now())
}

vm.runInNewContext(
  'Promise.resolve().then(() => loop());',
  { loop, console },
  { timeout: 5, microtaskMode: 'afterEvaluate' }
)

في هذه الحالة، سيتم تشغيل المهام الدقيقة المُجدولة من خلال promise.then() قبل العودة من vm.runInNewContext()، وسيتم مقاطعتها بواسطة وظيفة timeout. ينطبق هذا فقط على الكود الذي يعمل في vm.Context، لذلك على سبيل المثال، لا يأخذ vm.runInThisContext() هذا الخيار.

تُدخل استدعاءات الوظائف العودية في قائمة انتظار المهام الدقيقة للسياق الذي تم إنشاؤها فيه. على سبيل المثال، إذا تم استبدال () =\> loop() بـ loop فقط في المثال أعلاه، فسيتم دفع loop إلى قائمة انتظار المهام الدقيقة العالمية، لأنه دالة من السياق الخارجي (الرئيسي)، وبالتالي سيتمكن أيضًا من تجاوز المهلة الزمنية.

إذا تم توفير دوال جدولة غير متزامنة مثل process.nextTick()، و queueMicrotask()، و setTimeout()، و setImmediate()، إلخ، داخل vm.Context، فسيتم إضافة الدوال المُمررة إليها إلى قوائم الانتظار العالمية، والتي تُشاركها جميع السياقات. لذلك، لا يمكن التحكم في استدعاءات الوظائف العودية المُمررة إلى هذه الدوال من خلال المهلة الزمنية أيضًا.

دعم import() الديناميكي في واجهات برمجة تطبيقات التجميع

تدعم واجهات برمجة التطبيقات التالية خيار importModuleDynamically لتمكين import() الديناميكي في التعليمات البرمجية التي تم تجميعها بواسطة وحدة vm.

  • new vm.Script
  • vm.compileFunction()
  • new vm.SourceTextModule
  • vm.runInThisContext()
  • vm.runInContext()
  • vm.runInNewContext()
  • vm.createContext()

لا يزال هذا الخيار جزءًا من واجهة برمجة تطبيقات الوحدات التجريبية. نحن لا نوصي باستخدامه في بيئة إنتاج.

عندما لا يتم تحديد خيار importModuleDynamically أو يكون غير مُعرّف

إذا لم يتم تحديد هذا الخيار، أو إذا كان undefined، فيمكن لواجهات برمجة تطبيقات vm تجميع التعليمات البرمجية التي تحتوي على import()، ولكن عند تنفيذ التعليمات البرمجية المُجمّعة وتنفيذها فعليًا لـ import()، سترفض النتيجة مع ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING.

عندما يكون importModuleDynamically هو vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER

هذا الخيار غير مدعوم حاليًا لـ vm.SourceTextModule.

باستخدام هذا الخيار، عندما يتم بدء import() في التعليمات البرمجية المُجمّعة، ستستخدم Node.js مُحمّل ESM الافتراضي من السياق الرئيسي لتحميل الوحدة المطلوبة وإرجاعها إلى التعليمات البرمجية التي يتم تنفيذها.

يُتيح ذلك الوصول إلى وحدات Node.js المُدمجة مثل fs أو http إلى التعليمات البرمجية التي يتم تجميعها. إذا تم تنفيذ التعليمات البرمجية في سياق مختلف، فاعلم أن الكائنات التي تم إنشاؤها بواسطة الوحدات المُحمّلة من السياق الرئيسي لا تزال من السياق الرئيسي وليست instanceof فئات مُدمجة في السياق الجديد.

js
const { Script, constants } = require('node:vm')
const script = new Script('import("node:fs").then(({readFile}) => readFile instanceof Function)', {
  importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
})

// false: عنوان URL المُحمّل من السياق الرئيسي ليس مثيلًا لـ Function
// class في السياق الجديد.
script.runInNewContext().then(console.log)
js
import { Script, constants } from 'node:vm'

const script = new Script('import("node:fs").then(({readFile}) => readFile instanceof Function)', {
  importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
})

// false: عنوان URL المُحمّل من السياق الرئيسي ليس مثيلًا لـ Function
// class في السياق الجديد.
script.runInNewContext().then(console.log)

يسمح هذا الخيار أيضًا للبرنامج النصي أو الوظيفة بتحميل وحدات المستخدم:

js
import { Script, constants } from 'node:vm'
import { resolve } from 'node:path'
import { writeFileSync } from 'node:fs'

// كتابة test.js و test.txt إلى الدليل الذي يوجد فيه البرنامج النصي الحالي
// الذي يتم تشغيله.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(import.meta.dirname, 'test.json'), '{"hello": "world"}')

// تجميع برنامج نصي يقوم بتحميل test.mjs ثم test.json
// كما لو أن البرنامج النصي موجود في نفس الدليل.
const script = new Script(
  `(async function() {
    const { filename } = await import('./test.mjs');
    return import(filename, { with: { type: 'json' } })
  })();`,
  {
    filename: resolve(import.meta.dirname, 'test-with-default.js'),
    importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
  }
)

// { default: { hello: 'world' } }
script.runInThisContext().then(console.log)
js
const { Script, constants } = require('node:vm')
const { resolve } = require('node:path')
const { writeFileSync } = require('node:fs')

// كتابة test.js و test.txt إلى الدليل الذي يوجد فيه البرنامج النصي الحالي
// الذي يتم تشغيله.
writeFileSync(resolve(__dirname, 'test.mjs'), 'export const filename = "./test.json";')
writeFileSync(resolve(__dirname, 'test.json'), '{"hello": "world"}')

// تجميع برنامج نصي يقوم بتحميل test.mjs ثم test.json
// كما لو أن البرنامج النصي موجود في نفس الدليل.
const script = new Script(
  `(async function() {
    const { filename } = await import('./test.mjs');
    return import(filename, { with: { type: 'json' } })
  })();`,
  {
    filename: resolve(__dirname, 'test-with-default.js'),
    importModuleDynamically: constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
  }
)

// { default: { hello: 'world' } }
script.runInThisContext().then(console.log)

هناك بعض التحذيرات المتعلقة بتحميل وحدات المستخدم باستخدام المُحمّل الافتراضي من السياق الرئيسي:

عندما تكون importModuleDynamically دالة

عندما تكون importModuleDynamically دالة، سيتم استدعاؤها عند استدعاء import() في الكود المُجمَّع، ليتمكن المستخدمون من تخصيص كيفية تجميع وتقييم الوحدة المطلوبة. حاليًا، يجب تشغيل مثيل Node.js باستخدام علم --experimental-vm-modules لكي يعمل هذا الخيار. إذا لم يتم تعيين العلم، فسيتم تجاهل هذه المُراجعة. إذا كان الكود المُقيَّم يستدعي بالفعل import()، فسيتم رفض النتيجة مع ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING_FLAG.

تملك المُراجعة importModuleDynamically(specifier, referrer, importAttributes) التوقيع التالي:

  • specifier <string> مُحدد مُمرر إلى import()
  • referrer <vm.Script> | <Function> | <vm.SourceTextModule> | <Object> المُشير هو vm.Script المُجمَّع لـ new vm.Script, vm.runInThisContext, vm.runInContext و vm.runInNewContext. وهو Function المُجمَّع لـ vm.compileFunction, vm.SourceTextModule المُجمَّع لـ new vm.SourceTextModule, وسياق Object لـ vm.createContext().
  • importAttributes <Object> قيمة "with" المُمررة إلى المعلمة الاختيارية optionsExpression، أو كائن فارغ إذا لم يتم توفير أي قيمة.
  • ما يُرجعه: <Module Namespace Object> | <vm.Module> يُوصى بإرجاع vm.Module للاستفادة من تتبع الأخطاء، وتجنب المشاكل مع مساحات الأسماء التي تحتوي على تصدير دالة then.
js
// يجب تشغيل هذا البرنامج النصي باستخدام --experimental-vm-modules.
import { Script, SyntheticModule } from 'node:vm'

const script = new Script('import("foo.json", { with: { type: "json" } })', {
  async importModuleDynamically(specifier, referrer, importAttributes) {
    console.log(specifier) // 'foo.json'
    console.log(referrer) // البرنامج النصي المُجمَّع
    console.log(importAttributes) // { type: 'json' }
    const m = new SyntheticModule(['bar'], () => {})
    await m.link(() => {})
    m.setExport('bar', { hello: 'world' })
    return m
  },
})
const result = await script.runInThisContext()
console.log(result) //  { bar: { hello: 'world' } }
js
// يجب تشغيل هذا البرنامج النصي باستخدام --experimental-vm-modules.
const { Script, SyntheticModule } = require('node:vm')

;(async function main() {
  const script = new Script('import("foo.json", { with: { type: "json" } })', {
    async importModuleDynamically(specifier, referrer, importAttributes) {
      console.log(specifier) // 'foo.json'
      console.log(referrer) // البرنامج النصي المُجمَّع
      console.log(importAttributes) // { type: 'json' }
      const m = new SyntheticModule(['bar'], () => {})
      await m.link(() => {})
      m.setExport('bar', { hello: 'world' })
      return m
    },
  })
  const result = await script.runInThisContext()
  console.log(result) //  { bar: { hello: 'world' } }
})()