I'm trying to implement a way to run "sequentially written" async JS code in a Node.js VM and gain access to the respective context objects. I try to use the coming ES7 await
functionality, transpiled by babel.js
.
As it seems to me, script.runInContext() is run in the background, while the main loop continues, thus I can't reach the results from the VM's context.
My sample code is the following:
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);
Is there a way to retrieve asynchronous results from context evaluations in a synchronous way?
References:
I found a way to get this working... Basically it's using the this
variable for the context object inside the executed code, and calling a callback function from inside as the last operation:
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});