الوحدة النمطية VM (تنفيذ JavaScript)
[مستقر: 2 - مستقر]
مستقر: 2 الاستقرار: 2 - مستقر
الكود المصدري: lib/vm.js
تُمكّن الوحدة النمطية node:vm
من تجميع وتشغيل التعليمات البرمجية داخل سياقات الآلة الافتراضية V8.
الوحدة النمطية node:vm
ليست آلية أمان. لا تستخدمها لتشغيل تعليمات برمجية غير موثوق بها.
يمكن تجميع وتشغيل تعليمات JavaScript البرمجية على الفور أو تجميعها وحفظها وتشغيلها لاحقًا.
حالة الاستخدام الشائعة هي تشغيل التعليمات البرمجية في سياق 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
<string> كود JavaScript المراد تجميعه.options
<Object> | <string>filename
<string> يحدد اسم الملف المستخدم في آثار المكدس التي ينتجها هذا البرنامج النصي. افتراضي:'evalmachine.\<anonymous\>'
.lineOffset
<number> يحدد إزاحة رقم السطر التي يتم عرضها في آثار المكدس التي ينتجها هذا البرنامج النصي. افتراضي:0
.columnOffset
<number> يحدد إزاحة رقم عمود السطر الأول التي يتم عرضها في آثار المكدس التي ينتجها هذا البرنامج النصي. افتراضي:0
.cachedData
<Buffer> | <TypedArray> | <DataView> يوفرBuffer
أوTypedArray
أوDataView
اختياريًا مع بيانات ذاكرة التخزين المؤقت للكود الخاصة بـ V8 للمصدر المقدم. عند توفيره، سيتم تعيين قيمةcachedDataRejected
إما علىtrue
أوfalse
بناءً على قبول البيانات بواسطة V8.produceCachedData
<boolean> عندما يكونtrue
ولا توجدcachedData
، ستحاول V8 إنتاج بيانات ذاكرة التخزين المؤقت للكود لـcode
. عند النجاح، سيتم إنتاجBuffer
مع بيانات ذاكرة التخزين المؤقت للكود الخاصة بـ V8 وتخزينها في الخاصيةcachedData
لمثيلvm.Script
الذي تم إرجاعه. سيتم تعيين قيمةcachedDataProduced
إما علىtrue
أوfalse
بناءً على ما إذا تم إنتاج بيانات ذاكرة التخزين المؤقت للكود بنجاح. هذا الخيار مهمل لصالحscript.createCachedData()
. افتراضي:false
.importModuleDynamically
<Function> | <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
على أي حالات يمكن ملاحظتها في JavaScript. ذاكرة التخزين المؤقت للتعليمات البرمجية آمنة ليتم حفظها جنبًا إلى جنب مع مصدر البرنامج النصي وتستخدم لإنشاء مثيلات 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])
[سجل التغييرات]
الإصدار | التغييرات |
---|---|
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
<Object> | <vm.constants.DONT_CONTEXTIFY> | <undefined> إماvm.constants.DONT_CONTEXTIFY
أو كائن سيتم إضفاء سياق عليه. إذا كانundefined
، فسيتم إنشاء كائن مضفى عليه فارغ للتوافق مع الإصدارات السابقة.options
<Object>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> الأصل المقابل للسياق الذي تم إنشاؤه حديثًا لأغراض العرض. يجب تنسيق الأصل مثل عنوان URL، ولكن مع المخطط والمضيف والمنفذ فقط (إذا لزم الأمر)، مثل قيمة الخاصيةurl.origin
لكائنURL
. والأهم من ذلك، يجب أن تحذف هذه السلسلة الشرطة المائلة اللاحقة، لأن ذلك يشير إلى مسار. الافتراضي:''
.contextCodeGeneration
<Object>strings
<boolean> إذا تم تعيينه على false، فإن أي مكالمات إلىeval
أو مُنشئات الدالة (Function
,GeneratorFunction
, إلخ) ستطرحEvalError
. الافتراضي:true
.wasm
<boolean> إذا تم تعيينه على false، فإن أي محاولة لتجميع وحدة WebAssembly ستطرحWebAssembly.CompileError
. الافتراضي:true
.microtaskMode
<string> إذا تم تعيينه علىafterEvaluate
، فسيتم تشغيل المهام الصغيرة (المهام المجدولة من خلالPromise
s وasync function
s) مباشرة بعد تشغيل البرنامج النصي. يتم تضمينها في نطاقاتtimeout
وbreakOnSigint
في هذه الحالة.
الإرجاع: <any> نتيجة العبارة الأخيرة التي تم تنفيذها في البرنامج النصي.
هذه الطريقة هي اختصار لـ script.runInContext(vm.createContext(options), options)
. يفعل عدة أشياء في وقت واحد:
يقوم المثال التالي بتجميع التعليمات البرمجية التي تعين متغيرًا عامًا، ثم ينفذ التعليمات البرمجية عدة مرات في سياقات مختلفة. يتم تعيين المتغيرات العامة على كل context
فردي واحتوائها بداخله.
const vm = require('node:vm');
const script = new vm.Script('globalVar = "set"');
const contexts = [{}, {}, {}];
contexts.forEach((context) => {
script.runInNewContext(context);
});
console.log(contexts);
// Prints: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
// This would throw if the context is created from a contextified object.
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary
// global objects that can be frozen.
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);
// Prints: sourcemap.json
const vm = require('node:vm');
const script = new vm.Script(`
function myFunc() {}
//# sourceMappingURL=sourcemap.json
`);
console.log(script.sourceMapURL);
// Prints: 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. لا توجد أيضًا طريقة للتفاعل مع المحمل حتى الآن، على الرغم من التخطيط لدعمه.
import vm from 'node:vm';
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
// Step 1
//
// Create a Module by constructing a new `vm.SourceTextModule` object. This
// parses the provided source text, throwing a `SyntaxError` if anything goes
// wrong. By default, a Module is created in the top context. But here, we
// specify `contextifiedObject` as the context this Module belongs to.
//
// Here, we attempt to obtain the default export from the module "foo", and
// put it into local binding "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Step 2
//
// "Link" the imported dependencies of this Module to it.
//
// The provided linking callback (the "linker") accepts two arguments: the
// parent module (`bar` in this case) and the string that is the specifier of
// the imported module. The callback is expected to return a Module that
// corresponds to the provided specifier, with certain requirements documented
// in `module.link()`.
//
// If linking has not started for the returned Module, the same linker
// callback will be called on the returned Module.
//
// Even top-level Modules without dependencies must be explicitly linked. The
// callback provided would never be called, however.
//
// The link() method returns a Promise that will be resolved when all the
// Promises returned by the linker resolve.
//
// Note: This is a contrived example in that the linker function creates a new
// "foo" module every time it is called. In a full-fledged module system, a
// cache would probably be used to avoid duplicated modules.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// The "secret" variable refers to the global variable we added to
// "contextifiedObject" when creating the context.
export default secret;
`, { context: referencingModule.context });
// Using `contextifiedObject` instead of `referencingModule.context`
// here would work as well.
}
throw new Error(`Unable to resolve dependency: ${specifier}`);
}
await bar.link(linker);
// Step 3
//
// Evaluate the Module. The evaluate() method returns a promise which will
// resolve after the module has finished evaluating.
// Prints 42.
await bar.evaluate();
const vm = require('node:vm');
const contextifiedObject = vm.createContext({
secret: 42,
print: console.log,
});
(async () => {
// Step 1
//
// Create a Module by constructing a new `vm.SourceTextModule` object. This
// parses the provided source text, throwing a `SyntaxError` if anything goes
// wrong. By default, a Module is created in the top context. But here, we
// specify `contextifiedObject` as the context this Module belongs to.
//
// Here, we attempt to obtain the default export from the module "foo", and
// put it into local binding "secret".
const bar = new vm.SourceTextModule(`
import s from 'foo';
s;
print(s);
`, { context: contextifiedObject });
// Step 2
//
// "Link" the imported dependencies of this Module to it.
//
// The provided linking callback (the "linker") accepts two arguments: the
// parent module (`bar` in this case) and the string that is the specifier of
// the imported module. The callback is expected to return a Module that
// corresponds to the provided specifier, with certain requirements documented
// in `module.link()`.
//
// If linking has not started for the returned Module, the same linker
// callback will be called on the returned Module.
//
// Even top-level Modules without dependencies must be explicitly linked. The
// callback provided would never be called, however.
//
// The link() method returns a Promise that will be resolved when all the
// Promises returned by the linker resolve.
//
// Note: This is a contrived example in that the linker function creates a new
// "foo" module every time it is called. In a full-fledged module system, a
// cache would probably be used to avoid duplicated modules.
async function linker(specifier, referencingModule) {
if (specifier === 'foo') {
return new vm.SourceTextModule(`
// The "secret" variable refers to the global variable we added to
// "contextifiedObject" when creating the context.
export default secret;
`, { context: referencingModule.context });
// Using `contextifiedObject` instead of `referencingModule.context`
// here would work as well.
}
throw new Error(`Unable to resolve dependency: ${specifier}`);
}
await bar.link(linker);
// Step 3
//
// Evaluate the Module. The evaluate() method returns a promise which will
// resolve after the module has finished evaluating.
// Prints 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
الأصل. - يجب ألا تكون
status
الخاصة به'errored'
.
إذا كانت status
الخاصة بـ Module
المرتجع 'unlinked'
، فسيتم استدعاء هذه الطريقة بشكل متكرر على Module
المرتجع بنفس دالة linker
المتوفرة.
تُرجع link()
Promise
سيتم حله إما عند حل جميع مثيلات الربط إلى Module
صالح، أو سيتم رفضه إذا كانت دالة الربط إما تطرح استثناءً أو تُرجع Module
غير صالح.
تتوافق دالة الربط تقريبًا مع العملية المجردة HostResolveImportedModule المحددة التنفيذ في مواصفات ECMAScript، مع بعض الاختلافات الرئيسية:
- يُسمح بأن تكون دالة الربط غير متزامنة بينما 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
.
الفئة: vm.SourceTextModule
تمت إضافتها في: الإصدار 9.6.0
[مستقرة: 1 - تجريبية]
مستقرة: 1 الاستقرار: 1 - تجريبية
هذه الميزة متاحة فقط مع تمكين علامة سطر الأوامر --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
الذي يمثل كائنات للوحدة بالوصول إلى معلومات خارج context
المحدد. استخدم 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) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// 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) {
// Note: this object is created in the top context. As such,
// Object.getPrototypeOf(import.meta.prop) points to the
// Object.prototype in the top context rather than that in
// the contextified object.
meta.prop = {};
},
});
// Since module has no dependencies, the linker function will never be called.
await module.link(() => {});
await module.evaluate();
// Now, Object.prototype.secret will be equal to 42.
//
// To fix this problem, replace
// meta.prop = {};
// above with
// 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
[مستقر: 1 - تجريبي]
مستقر: 1 الاستقرار: 1 - تجريبي
تتوفر هذه الميزة فقط مع تمكين علامة سطر الأوامر --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> الكائن contextified كما تم إرجاعه بواسطة طريقة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()
الديناميكي في واجهات برمجة تطبيقات الترجمة.Returns: <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> إذا تم تعيينه على خطأ، فإن أي استدعاءات لـeval
أو منشئات الدالات (Function
،GeneratorFunction
، إلخ) ستطرحEvalError
. افتراضي:true
.wasm
<boolean> إذا تم تعيينه على خطأ، فإن أي محاولة لتجميع وحدة 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);
// Prints: { globalVar: 2 }
console.log(global.globalVar);
// Prints: 3
إذا تم حذف contextObject
(أو تم تمريره بشكل صريح كـ undefined
)، فسيتم إرجاع كائن مؤطر في سياق فارغ جديد.
عندما يكون الكائن العام في السياق الذي تم إنشاؤه حديثًا مؤطرًا في سياق، فإنه يحتوي على بعض الغرابة مقارنة بالكائنات العامة العادية. على سبيل المثال، لا يمكن تجميده. لإنشاء سياق بدون غرابة التأطير في سياق، قم بتمرير vm.constants.DONT_CONTEXTIFY
كـ contextObject
. انظر وثائق vm.constants.DONT_CONTEXTIFY
للحصول على التفاصيل.
تعد الطريقة vm.createContext()
مفيدة في المقام الأول لإنشاء سياق واحد يمكن استخدامه لتشغيل برامج نصية متعددة. على سبيل المثال، إذا كانت تحاكي متصفح ويب، فيمكن استخدام الطريقة لإنشاء سياق واحد يمثل الكائن العام للنافذة، ثم تشغيل جميع علامات \<script\>
معًا داخل هذا السياق.
يتم عرض name
و origin
المقدمين للسياق من خلال واجهة برمجة تطبيقات Inspector.
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
<الكائن> اختياري.mode
<سلسلة نصية> إما'summary'
أو'detailed'
. في وضع الملخص، سيتم إرجاع الذاكرة التي تم قياسها للسياق الرئيسي فقط. في الوضع التفصيلي، سيتم إرجاع الذاكرة التي تم قياسها لجميع السياقات المعروفة لعزل V8 الحالي. افتراضي:'summary'
execution
<سلسلة نصية> إما'default'
أو'eager'
. مع التنفيذ الافتراضي، لن يتم حل الوعد حتى بعد بدء جمع البيانات المهملة المجدول التالي، الأمر الذي قد يستغرق بعض الوقت (أو لا يحدث أبدًا إذا انتهى البرنامج قبل عملية GC التالية). مع التنفيذ السريع، ستبدأ عملية GC على الفور لقياس الذاكرة. افتراضي:'default'
القيمة المعادة: <الوعد> إذا تم قياس الذاكرة بنجاح، فسيتم حل الوعد بكائن يحتوي على معلومات حول استخدام الذاكرة. وإلا سيتم رفضه مع الخطأ
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
<string> رمز JavaScript المراد تجميعه وتشغيله.contextifiedObject
<Object> الكائن الذي تم تحويله إلى سياق والذي سيستخدم كـglobal
عند تجميع وتشغيلcode
.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
.cachedData
<Buffer> | <TypedArray> | <DataView> يوفرBuffer
أوTypedArray
أوDataView
اختياريًا مع بيانات ذاكرة التخزين المؤقت للتعليمات البرمجية V8 للمصدر المقدم.importModuleDynamically
<Function> | <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);
// Prints: { globalVar: 1024 }
vm.runInNewContext(code[, 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 . |
الإصدار 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> الأصل المطابق للسياق الذي تم إنشاؤه حديثًا لأغراض العرض. يجب تنسيق الأصل مثل عنوان 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
) مباشرة بعد تشغيل البرنامج النصي. يتم تضمينها في نطاقات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
<string> كود JavaScript المراد تجميعه وتشغيله.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
.cachedData
<Buffer> | <TypedArray> | <DataView> يوفرBuffer
أوTypedArray
أوDataView
اختياريًا مع بيانات ذاكرة التخزين المؤقت للتعليمات البرمجية لـ V8 للمصدر المقدم.importModuleDynamically
<Function> | <vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER> يُستخدم لتحديد كيفية تحميل الوحدات النمطية أثناء تقييم هذا البرنامج النصي عند استدعاءimport()
. هذا الخيار هو جزء من واجهة برمجة تطبيقات الوحدات النمطية التجريبية. لا نوصي باستخدامه في بيئة إنتاج. للحصول على معلومات مفصلة، راجع دعمimport()
الديناميكي في واجهات برمجة تطبيقات التجميع.
الإرجاع: <any> نتيجة آخر عبارة تم تنفيذها في البرنامج النصي.
يقوم vm.runInThisContext()
بتجميع code
وتشغيله في سياق global
الحالي وإرجاع النتيجة. لا يمكن للتعليمات البرمجية التي يتم تشغيلها الوصول إلى النطاق المحلي، ولكن يمكنها الوصول إلى كائن global
الحالي.
إذا كانت options
سلسلة، فإنه يحدد اسم الملف.
يوضح المثال التالي استخدام كل من vm.runInThisContext()
ووظيفة JavaScript eval()
لتشغيل نفس التعليمات البرمجية:
const vm = require('node:vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('localVar = "vm";');
console.log(`vmResult: '${vmResult}', localVar: '${localVar}'`);
// Prints: vmResult: 'vm', localVar: 'initial value'
const evalResult = eval('localVar = "eval";');
console.log(`evalResult: '${evalResult}', localVar: '${localVar}'`);
// Prints: 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()
في الحالة أعلاه مع السياق الذي تم تمريرها منه. قد يؤدي ذلك إلى مخاطر عند تنفيذ تعليمات برمجية غير موثوق بها، على سبيل المثال تغيير الكائنات في السياق بطرق غير مرغوب فيها.
ماذا يعني "تحديد سياق" كائن؟
يتم تنفيذ جميع JavaScript داخل Node.js في نطاق "سياق". وفقًا لـ دليل V8 Embedder:
عند استدعاء الأسلوب vm.createContext()
مع كائن، سيتم استخدام وسيطة contextObject
لتغليف الكائن العام لمثيل جديد من سياق V8 (إذا كانت contextObject
هي undefined
، فسيتم إنشاء كائن جديد من السياق الحالي قبل تحديد سياقه). يوفر سياق V8 هذا code
الذي يتم تشغيله باستخدام أساليب وحدة 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
s و async function
s جدولة المهام التي يتم تشغيلها بواسطة محرك 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 loaded from the main context is not an instance of the Function
// class in the new context.
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 loaded from the main context is not an instance of the Function
// class in the new context.
script.runInNewContext().then(console.log);
يسمح هذا الخيار أيضًا للبرنامج النصي أو الوظيفة بتحميل وحدات المستخدم:
import { Script, constants } from 'node:vm';
import { resolve } from 'node:path';
import { writeFileSync } from 'node:fs';
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(import.meta.dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(import.meta.dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same directory.
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');
// Write test.js and test.txt to the directory where the current script
// being run is located.
writeFileSync(resolve(__dirname, 'test.mjs'),
'export const filename = "./test.json";');
writeFileSync(resolve(__dirname, 'test.json'),
'{"hello": "world"}');
// Compile a script that loads test.mjs and then test.json
// as if the script is placed in the same directory.
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
للاستفادة من تتبع الأخطاء، وتجنب المشكلات المتعلقة بـ namespaces التي تحتوي على صادرات دالة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' } }
})();