2016-11-14 1 views
0

Как получить значение в контексте узла vm.Получение значений из модуля ядра Vode

Если я создаю контекст и запускаю скрипт в нем, я использую util.inspect([[context]])?

И если я это сделаю, он вернется в сериализацию?

по какой-то причине, когда я util.inspect("null") он возвращается с '\'null'\'

знает любой почему, а также то, что лучший способ, чтобы получить значения из контекста запуска в модуле узлов Vm?

Я также сделал несколько микро-тестов, и кажется, что создание нового контекста происходит намного медленнее, чем запуск его в thisContext. Также, когда я избавляюсь от тайм-аута, похоже, он работает намного быстрее.

Поэтому я хотел бы использовать этот контекст, не используя глобальные переменные, чтобы не вызвать утечку, а также попытаться ускорить выполнение этого.

Контекст этого кода заключается в том, что я пытаюсь добавить в песочницу катастрофическое регулярное выражение.

global.mapperContext = { 
    result: false 
}; 

const scriptString = ` 
    global.mapperContext.result = true; 

    if ("${string}".match(${regex})) { 
    global.mapperContext.result = false; 
    } 
`; 

const vmScript = new vm.script(scriptString); 

try { 
    vmScript.runInThisContext({ timeout: 1000 }); 
} catch (e) { 
    // Do something with error 
} 

// This works but I dont like attaching things to the global object. 
// I could cause memory leaks... 
console.log(global.mapperContext); 
const mapperContext = { result }; 

const scriptString = ` 
(function IIFE() { 

    result = true; 

    if ("${string}".match(${regex})) { 
    result = false; 
    } 

})() 
`; 

const sandbox = vm.createContext(mapperContext); 
const script = new vm.script(scriptString); 

script.runInContext(script, sandbox, {timeout: 1000}); 

// This result is serialized and is hard to parse. 
util.inspect(sandbox.result); 
+0

Можете ли вы предоставить простой (код) пример того, чего вы пытаетесь достичь? – mscdex

+0

@mscdex Я обновил билет. –

ответ

2

Ваш код почти правильно, но ваш script.runInContext() должен вместо этого выглядеть следующим образом:

script.runInContext(sandbox, {timeout: 1000}); 

С учетом этого изменения, вы должны увидеть sandbox.result как логическое значение.

Что касается производительности, вы должны иметь возможность повторно использовать переменные sandbox для нескольких вызовов до script.runInContext(), так что это поможет некоторым.

Что-то еще, что вы можете попробовать, это создать общий сценарий, который можно повторно использовать для любых значений строк и регулярных выражений, передав их в один и тот же сценарий вместо создания новых скриптов для каждого набора значений. Например:

const vm = require('vm'); 
const mapperContext = { result: false, string: 'bar', regex: /baa/ }; 

const scriptString = ` 
(function IIFE() { 

    result = true; 

    if (regex.test(string)) { 
    result = false; 
    } 

})() 
`; 

// Only perform these two calls once ... 
const sandbox = vm.createContext(mapperContext); 
const script = new vm.Script(scriptString); 

// ... and then run the script as many times as needed ... 
script.runInContext(sandbox, {timeout: 1000}); 
console.dir(sandbox.result); 

// ... 

mapperContext.string = 'foo'; 
mapperContext.regex = /foo/; 
script.runInContext(sandbox, {timeout: 1000}); 
console.dir(sandbox.result); 

// ... 

Один поворот, вы можете также рассмотреть вопрос о том, чтобы просто возвращать логическое значение вместо установки глобальной (result) внутри функции, таким образом возвращаемое значение доступна в качестве возвращаемого значения script.runInContext(). Например:

const vm = require('vm'); 
const mapperContext = { string: 'bar', regex: /baa/ }; 
const scriptString = 'regex.test(string);'; 
const sandbox = vm.createContext(mapperContext); 
const script = new vm.Script(scriptString); 
var ret; 

ret = script.runInContext(sandbox, {timeout: 1000}); 
console.dir(ret); 

// ... 

mapperContext.string = 'foo'; 
mapperContext.regex = /foo/; 
ret = script.runInContext(sandbox, {timeout: 1000}); 
console.dir(ret); 

// ... 

Наконец, конечно, вы хотите, чтобы убедиться, чтобы обернуть вызовы script.runInContext() в примерочных поймать блока в случае, если есть тайм-аут. Для производительности (pre-node v7.0.0) вы захотите изолировать этот try-catch в отдельной функции, так как до узла v7 V8 навсегда деоптимизировал всю функцию, содержащую try-catch (или try-finally):

const vm = require('vm'); 

function tryRun(string, regex, timeout) { 
    var ctx = tryRun.ctx; 
    var sandbox = tryRun.sandbox; 
    var script = tryRun.script; 
    if (!ctx) { 
    ctx = tryRun.ctx = { string: string, regex: regex }; 
    sandbox = tryRun.sandbox = vm.createContext(ctx); 
    script = tryRun.script = new vm.Script('regex.test(string)'); 
    } else { 
    ctx.string = string; 
    ctx.regex = regex; 
    } 
    timeout = timeout || 1000; 
    try { 
    return script.runInContext(sandbox, {timeout}); 
    } catch (ex) { 
    return ex; 
    } 
} 

console.dir(tryRun('bar', /baa/)); 

// ... 

console.dir(tryRun('foo', /foo/)); 

// ... 

// Example of timeout 
console.dir(tryRun('xxxx'.repeat(100), /(x+x+)+y/)); 

// ... 
+0

Спасибо, кучка. Я дам им выстрел! –

Смежные вопросы