【问题标题】:How to retrieve async results from a Node.js VM script using ES7 syntax如何使用 ES7 语法从 Node.js VM 脚本中检索异步结果
【发布时间】:2016-03-13 15:05:09
【问题描述】:

我正在尝试实现一种在 Node.js VM 中运行“按顺序编写”的异步 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);

有没有办法以同步的方式从上下文评估中检索异步结果?

参考资料:

【问题讨论】:

  • 我必须选择不,这是不可能的。如果不能在 ES5 或 ES2015 中完成,也无法在 ES7 中转译为 ES5 或 ES2015,除非使其同步而不是异步。
  • 不确定是否“无法完成”...代码本身是正确的并且可以执行。这只是获得结果的问题。我认为问题在于我必须将 ES7 代码包装在异步 IIF 中,这会导致无法访问恕我直言...
  • 嗯,不。 console.log 将在异步操作完成之前发生。它与达到它无关。尝试将 console.log 包装在一个长的 setTimeout 中,看看我的意思。
  • 是的,但如果我执行标准 ES5 而不进行转译和必要的 IIF,恕我直言,代码将同步执行...看看我正在尝试实现的类似示例:@987654326 @
  • 啊,我才意识到为什么每个人都对这种异步/等待语法大发雷霆。它使这成为可能:pastebin.com/9hiEADe3 这基本上就是您想要做的吗? (我不明白 vm 模块是如何工作的。所以我改为在我自己的沙箱中运行它,该沙箱使用 require 挂钩编译到 ES5)

标签: node.js async-await babeljs ecmascript-2016


【解决方案1】:
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();')

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

您可以删除var,而不是用this. 替换var

这将使变量成为上下文的全局变量,然后可以在 vm 外部访问。

【讨论】:

    【解决方案3】:
    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
    })();
    

    Gist here

    【讨论】:

      【解决方案4】:

      我找到了一种让它工作的方法......基本上它使用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});
      

      【讨论】:

        猜你喜欢
        • 2018-07-21
        • 2017-07-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-22
        • 2015-08-29
        • 2019-10-11
        相关资源
        最近更新 更多