如何使用 ES7 语法从 Node.js VM 脚本检索异步结果
How to retrieve async results from a Node.js VM script using ES7 syntax
我正在尝试在 Node.js VM 中实现一种 运行 "sequentially written" 异步 JS 代码并获得对相应上下文对象的访问权限的方法。我尝试使用即将到来的 ES7 await
功能,由 babel.js
.
转译
在我看来,script.runInContext() 在后台 运行,而主循环仍在继续,因此我无法从 VM 的上下文中获取结果。
我的示例代码如下:
var vm = require('vm');
var request = require('request-promise');
var babel = require("babel-core");
// VM context object
var contextCache = {
context: {
request: request
}
};
// ES 7 code
var code = "var res = await request('http://www.google.de')";
// Wrap the code
code = "(async function() { " + code + " })()";
// Transpile code ES7 -> ES5
var regeneratedCode = babel.transform(code, { "ast": false, "presets": ["stage-0"] }).code
// Create VM context
var vmContext = new vm.createContext(contextCache.context);
// Create virtual script
var script = new vm.Script(regeneratedCode);
// Run script
script.runInContext(vmContext, {displayErrors: true, timeout: 30000});
// Check if variable was set -> Is undefined
console.log(contextCache.context.res);
有没有办法以同步方式从上下文评估中检索异步结果?
参考文献:
我找到了一种方法让这个工作...基本上它使用 this
变量作为执行代码中的上下文对象,并从内部调用回调函数作为最后一个操作:
var vm = require('vm');
var babel = require("babel-core");
// VM context object
var context = {
require: require,
callback: function(error) {
if (error) {
console.log(error.stack);
} else {
console.log(this.response);
}
}
};
// ES 7 code
var code = "var request = require('request-promise'); var response = await request({ url: 'https://graph.facebook.com/?id=http://news.ycombinator.com', json: true })";
// Wrap the code
code = "'use strict'; async function run() { try { " + code.replace(/var /g, "this.") + "; this.callback(null); } catch(error) { this.callback(error); } }; run.apply(this)";
// Transpile code ES7 -> ES5
var regeneratedCode = babel.transform(code, { "ast": false, "presets": ["stage-0"] }).code;
// Create VM context
var vmContext = new vm.createContext(context);
// Create virtual script
var script = new vm.Script(regeneratedCode);
// Run script
script.runInContext(vmContext, {displayErrors: true, timeout: 30000});
我们的想法是,如果脚本上有一些异步操作,则知道脚本何时结束。
我们可以通过将 promise 的 resolve 函数附加到上下文来在 Promise 中的 vm 上执行脚本。然后在脚本上执行附加在上下文中的解析函数。
这向您保证,在解决此承诺后,您现在可以获取异步函数的结果。
const vm = require('vm');
(async () => {
const sandbox = {
a: 1
};
await new Promise(resolve => {
sandbox.resolve = resolve;
const code = 'Promise.resolve(2).then(result => {a = result; resolve();})';
const script = new vm.Script(code);
const context = new vm.createContext(sandbox);
script.runInContext(context);
});
console.log(sandbox.a); // 2
})();
无需将 var
替换为 this.
,您只需删除 var
.
这将使变量成为上下文的全局变量,然后可以在虚拟机外部访问该变量。
async function runScript(code, context = {}, options = {}) {
return new Promise((resolve, reject) => {
const { timeout = 120 * 1000, breakOnSigint = true } = options;
const script = new Script(`(async()=>{${code}})()`);
script.runInContext(createContext({
...context,
resolve,
reject,
}), {
timeout,
breakOnSigint,
});
});
}
演示
await runScript('some code; resolve();')
我正在尝试在 Node.js VM 中实现一种 运行 "sequentially written" 异步 JS 代码并获得对相应上下文对象的访问权限的方法。我尝试使用即将到来的 ES7 await
功能,由 babel.js
.
在我看来,script.runInContext() 在后台 运行,而主循环仍在继续,因此我无法从 VM 的上下文中获取结果。
我的示例代码如下:
var vm = require('vm');
var request = require('request-promise');
var babel = require("babel-core");
// VM context object
var contextCache = {
context: {
request: request
}
};
// ES 7 code
var code = "var res = await request('http://www.google.de')";
// Wrap the code
code = "(async function() { " + code + " })()";
// Transpile code ES7 -> ES5
var regeneratedCode = babel.transform(code, { "ast": false, "presets": ["stage-0"] }).code
// Create VM context
var vmContext = new vm.createContext(contextCache.context);
// Create virtual script
var script = new vm.Script(regeneratedCode);
// Run script
script.runInContext(vmContext, {displayErrors: true, timeout: 30000});
// Check if variable was set -> Is undefined
console.log(contextCache.context.res);
有没有办法以同步方式从上下文评估中检索异步结果?
参考文献:
我找到了一种方法让这个工作...基本上它使用 this
变量作为执行代码中的上下文对象,并从内部调用回调函数作为最后一个操作:
var vm = require('vm');
var babel = require("babel-core");
// VM context object
var context = {
require: require,
callback: function(error) {
if (error) {
console.log(error.stack);
} else {
console.log(this.response);
}
}
};
// ES 7 code
var code = "var request = require('request-promise'); var response = await request({ url: 'https://graph.facebook.com/?id=http://news.ycombinator.com', json: true })";
// Wrap the code
code = "'use strict'; async function run() { try { " + code.replace(/var /g, "this.") + "; this.callback(null); } catch(error) { this.callback(error); } }; run.apply(this)";
// Transpile code ES7 -> ES5
var regeneratedCode = babel.transform(code, { "ast": false, "presets": ["stage-0"] }).code;
// Create VM context
var vmContext = new vm.createContext(context);
// Create virtual script
var script = new vm.Script(regeneratedCode);
// Run script
script.runInContext(vmContext, {displayErrors: true, timeout: 30000});
我们的想法是,如果脚本上有一些异步操作,则知道脚本何时结束。 我们可以通过将 promise 的 resolve 函数附加到上下文来在 Promise 中的 vm 上执行脚本。然后在脚本上执行附加在上下文中的解析函数。 这向您保证,在解决此承诺后,您现在可以获取异步函数的结果。
const vm = require('vm');
(async () => {
const sandbox = {
a: 1
};
await new Promise(resolve => {
sandbox.resolve = resolve;
const code = 'Promise.resolve(2).then(result => {a = result; resolve();})';
const script = new vm.Script(code);
const context = new vm.createContext(sandbox);
script.runInContext(context);
});
console.log(sandbox.a); // 2
})();
无需将 var
替换为 this.
,您只需删除 var
.
这将使变量成为上下文的全局变量,然后可以在虚拟机外部访问该变量。
async function runScript(code, context = {}, options = {}) {
return new Promise((resolve, reject) => {
const { timeout = 120 * 1000, breakOnSigint = true } = options;
const script = new Script(`(async()=>{${code}})()`);
script.runInContext(createContext({
...context,
resolve,
reject,
}), {
timeout,
breakOnSigint,
});
});
}
演示
await runScript('some code; resolve();')