آلة افتراضية (تنفيذ جافا سكريبت)
[مستقر: 2 - مستقر]
مستقر: 2 استقرار: 2 - مستقر
رمز المصدر: lib/vm.js
تتيح وحدة node:vm
تجميع وتشغيل التعليمات البرمجية داخل سياقات آلة V8 الافتراضية.
وحدة node:vm
ليست آلية أمان. لا تستخدمها لتشغيل التعليمات البرمجية غير الموثوق بها.
يمكن تجميع وتشغيل تعليمات برمجة جافا سكريبت على الفور أو تجميعها وحفظها وتشغيلها لاحقًا.
حالة استخدام شائعة هي تشغيل التعليمات البرمجية في سياق V8 مختلف. هذا يعني أن التعليمات البرمجية التي يتم استدعاؤها لها كائن عالمي مختلف عن التعليمات البرمجية التي تستدعيها.
يمكن للمرء توفير السياق عن طريق وضع السياق لكائن. تعامل التعليمات البرمجية التي يتم استدعاؤها أي خاصية في السياق مثل متغير عالمي. أي تغييرات تطرأ على المتغيرات العالمية بسبب التعليمات البرمجية التي يتم استدعاؤها تنعكس في كائن السياق.
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
- القيمة المُرجعه: <Buffer>
يُنشئ ذاكرة تخزين مؤقتة للرمز والتي يمكن استخدامها مع خيار cachedData
الخاص بمنشئ Script
. يُرجع Buffer
. يمكن استدعاء هذه الطريقة في أي وقت وعدد غير محدود من المرات.
لا تحتوي ذاكرة التخزين المؤقتة للرمز الخاصة بـ Script
على أي حالات قابلة للملاحظة في جافا سكريبت. من الآمن حفظ ذاكرة التخزين المؤقتة للرمز جنبًا إلى جنب مع مصدر البرنامج النصي واستخدامها لإنشاء مثيلات جديدة من Script
عدة مرات.
يمكن تمييز الدوال في مصدر Script
على أنها مُجمّعة بشكل كسول، ولا يتم تجميعها عند إنشاء Script
. سيتم تجميع هذه الدوال عند استدعائها لأول مرة. تقوم ذاكرة التخزين المؤقتة للرمز بترتيب البيانات الوصفية التي يعرفها V8 حاليًا حول Script
والتي يمكن استخدامها لتسريع عمليات التجميع المستقبلية.
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
.
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)
. إنها تقوم بأشياء متعددة في وقت واحد:
يوضح المثال التالي تجميع الرمز الذي يُعيّن متغيرًا عامًا، ثم ينفذ الرمز عدة مرات في سياقات مختلفة. يتم تعيين المتغيرات العامة على كل سياق فردي واحتوائها داخله.
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
ثم تقوم بتنفيذ هذه التعليمات البرمجية عدة مرات:
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 لخريطة المصدر.
import vm from 'node:vm'
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`)
console.log(script.sourceMapURL)
// يطبع: sourcemap.json
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
هذه الميزة متاحة فقط مع تمكين علم الأمر --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 حتى الآن، على الرغم من أن الدعم مخطط له.
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()
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، مع بعض الاختلافات الرئيسية:
- يُسمح بأن تكون دالة linker غير متزامنة بينما HostResolveImportedModule متزامنة.
التنفيذ الفعلي لـ 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
هذه الميزة متاحة فقط مع تمكين علم الأمر --experimental-vm-modules
.
- يمتد: <vm.Module>
توفر فئة 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()
لإنشاء كائنات في سياق مُحدد.
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);
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
- قيم الإرجاع: <Buffer>
يُنشئ ذاكرة تخزين مؤقتة للشيفرة يمكن استخدامها مع خيار cachedData
الخاص بمنشئ SourceTextModule
. يُرجع مُخزن مؤقت Buffer
. يمكن استدعاء هذه الطريقة أي عدد من المرات قبل تقييم الوحدة.
لا تحتوي ذاكرة التخزين المؤقتة للشيفرة الخاصة بـ SourceTextModule
على أي حالات قابلة للملاحظة في JavaScript. من الآمن حفظ ذاكرة التخزين المؤقتة للشيفرة مع مصدر البرنامج النصي واستخدامها لإنشاء مثيلات جديدة من SourceTextModule
عدة مرات.
يمكن تمييز الدوال الموجودة في مصدر SourceTextModule
على أنها مُجمعة بشكل كسول، ولا يتم تجميعها عند إنشاء SourceTextModule
. سيتم تجميع هذه الدوال عند استدعائها لأول مرة. تقوم ذاكرة التخزين المؤقتة للشيفرة بتسلسل البيانات الوصفية التي يعرفها V8 حاليًا حول SourceTextModule
والتي يمكنه استخدامها لتسريع عمليات التجميع المستقبلية.
// إنشاء وحدة أولية
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
هذه الميزة متوفرة فقط مع تمكين علم الأمر --experimental-vm-modules
.
- يمتد: <vm.Module>
يوفر فئة vm.SyntheticModule
سجل الوحدة الاصطناعية كما هو محدد في مواصفات WebIDL. الغرض من الوحدات الاصطناعية هو توفير واجهة عامة لعرض مصادر غير JavaScript على رسوم بيانية لوحدات ECMAScript.
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
تُستخدم هذه الطريقة بعد ربط الوحدة النمطية لتعيين قيم التصدير. إذا تم استدعاؤها قبل ربط الوحدة النمطية، فسيتم طرح خطأ ERR_VM_MODULE_STATUS
.
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)
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، ستظل المتغيرات العالمية دون تغيير.
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
قياس الذاكرة المعروفة لـ 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 الحالي.
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
سلسلة، فإنها تحدد اسم الملف.
يوضح المثال التالي تجميع وتنفيذ برامج نصية مختلفة باستخدام كائن واحد معرّف بالسياق:
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
، فسيتم إنشاء كائن فارغ تم وضعه في سياق من أجل التوافق مع الإصدارات السابقة.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 function
s) فورًا بعد تشغيل البرنامج النصي. وهي مدرجة في نطاقاتtimeout
وbreakOnSigint
في تلك الحالة.
قيمة الإرجاع: <any> نتيجة آخر بيان تم تنفيذه في البرنامج النصي.
هذه الطريقة اختصار لـ (new vm.Script(code, options)).runInContext(vm.createContext(options), options)
. إذا كانت options
سلسلة، فإنها تحدد اسم الملف.
إنها تقوم بأشياء كثيرة في وقت واحد:
يوضح المثال التالي تجميع وتنفيذ التعليمات البرمجية التي تزيد متغيرًا عالميًا وتعيين متغير جديد. توجد هذه المتغيرات العالمية في contextObject
.
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
<سلسلة> شفرة جافاسكريبت المراد تجميعها وتشغيلها.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()
لتشغيل نفس الكود:
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
الممررة إليه. على سبيل المثال:
'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
في السياق الخارجي.
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
داخل السياق الجديد بشكل أقرب إلى قيمة عادية.
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
في السياق الجديد، ويمكن تعديله من خارج السياق، ويمكن استخدامه للوصول إلى المدمجات في السياق الجديد مباشرةً.
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 ملي ثانية بجدولة حلقة لا نهائية للتشغيل بعد حل وعد. لا يتم مقاطعة الحلقة المُجدولة أبدًا بواسطة المهلة الزمنية:
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
:
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
فئات مُدمجة في السياق الجديد.
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)
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)
يسمح هذا الخيار أيضًا للبرنامج النصي أو الوظيفة بتحميل وحدات المستخدم:
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)
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
.
// يجب تشغيل هذا البرنامج النصي باستخدام --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' } }
// يجب تشغيل هذا البرنامج النصي باستخدام --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' } }
})()