SoFunction
Updated on 2025-03-03

Dynamic execution scripts

Recently, a virtual machine module has been added. In fact, it cannot be said that it is new. It just exposes some internal interfaces, and it has been there since. We can see these codes from node/src/:

var Script = ('evals').NodeScript;
var runInThisContext = ;
 
  = function(script) {
  return [0] + script + [1];
 };
 
  = [
  '(function (exports, require, module, __filename, __dirname) { ',
  '\n});'
 ];
 
  = function() {
  var source = ();
  source = (source);
 
  var fn = runInThisContext(source, , true);
  fn(, , this, );
 
   = true;
 };

The Script object in it is very similar to the object returned by require('vm'), but in essence, the vm module is the encapsulation of the Script object.

var Script = ('evals').NodeScript;
(Script)
/**
{ [Function: NodeScript]
 createContext: [Function],
 runInContext: [Function],
 runInThisContext: [Function],
 runInNewContext: [Function] }
 
*/
(require('vm'))
{ Script: 
  { [Function: NodeScript]
   createContext: [Function],
   runInContext: [Function],
   runInThisContext: [Function],
   runInNewContext: [Function] },
 createScript: [Function],
 createContext: [Function],
 runInContext: [Function],
 runInThisContext: [Function],
 runInNewContext: [Function] }

Among them, runInThisContext is equivalent to executing code in a brand new environment and will not affect the object in the current scope. runInNewContext and runInContext can be specified as context objects, the difference is a normal object or a context object. In other words, runInNewContext and runInContext can locally affect objects in the current scope. To fully interact with the current environment, dangerous evals are required. In the built-in loading system, it is obviously not so courageous, and the runInThisContext is used. And I did a lot of work before this, such as wrapping the contents of the user's JS file with a layer ( ), and other scatter operations, and synchronous operations, which is actually a very efficient loading method. The only benefit is that the synchronization is used, making the code much easier to write.

In github, some people have compared the performance of these methods of dynamically executing scripts:

var vm = require('vm'),
 code = 'var square = n * n;',
 fn = new Function('n', code),
 script = (code),
 sandbox;
 
n = 5;
sandbox = { n: n };
 
benchmark = function(title, funk) {
 var end, i, start;
 start = new Date;
 for (i = 0; i < 5000; i++) {
  funk();
 }
 end = new Date;
 (title + ': ' + (end - start) + 'ms');
}
 
var ctx = (sandbox);
benchmark('',   function() { (code); });
benchmark('',   function() { (code, sandbox); });
benchmark('', function() { (); });
benchmark('', function() { (sandbox); });
benchmark('', function() { (ctx); });
benchmark('fn',           function() { fn(n); });
/**
: 212ms
: 2222ms
: 6ms
: 1876ms
: 44ms
fn: 0ms
 
*/

From this we can see that the V8 method function is the perfect win!

The above is the entire content of this article. I hope you can give you a reference and I hope you can support me more.