You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中实现eval()逐语句暂停或使用可暂停虚拟机?

解决方案:逐行可控执行用户代码

核心思路:AST转换 + 生成器函数

直接修改用户代码插入异步暂停逻辑容易触发兼容问题,更可靠的方式是通过解析用户代码为抽象语法树(AST),将代码转换为可逐步控制的生成器函数,无需手动修改用户代码文本,就能实现每执行完一个语句后暂停,等待游戏视图同步完成后再继续执行。

具体实现步骤

  1. 解析用户代码为AST
    使用@babel/parser或acorn将用户代码解析为抽象语法树,精准识别语句结构,规避字符串替换的风险:
import { parse } from '@babel/parser';
const userCode = `
  function controlPlayer() {
    move('up');
    move('right');
    attack();
  }
  controlPlayer();
`;
const ast = parse(userCode, { sourceType: 'script' });
  1. 转换AST为带暂停点的生成器函数
    用@babel/traverse遍历AST,将每个可执行语句包裹成yield表达式,再通过@babel/generator生成转换后的代码并包装为生成器函数:
import traverse from '@babel/traverse';
import generate from '@babel/generator';
import * as t from '@babel/types';

traverse(ast, {
  ExpressionStatement(path) {
    path.replaceWith(t.yieldExpression(path.node.expression));
  },
  BlockStatement(path) {
    path.node.body = path.node.body.map(stmt => {
      if (t.isExpressionStatement(stmt)) {
        return t.yieldExpression(stmt.expression);
      }
      return stmt;
    });
  }
});

const transformedCode = `
  function* runUserCode() {
    ${generate(ast).code}
  }
`;
  1. 控制生成器的执行节奏
    创建生成器迭代器,通过异步函数控制执行流程,每执行到yield点就等待游戏视图同步(比如角色移动动画完成),再触发下一步:
// 定义用户代码依赖的游戏函数
const move = (direction) => {
  // 触发角色移动逻辑
  console.log(`Moving ${direction}`);
  // 返回Promise等待动画完成
  return new Promise(resolve => setTimeout(resolve, 1000));
};

// 执行转换后的代码得到生成器函数
eval(transformedCode);
const iterator = runUserCode();

// 逐步执行逻辑
async function executeStepByStep() {
  let result = iterator.next();
  while (!result.done) {
    if (result.value instanceof Promise) {
      await result.value;
    }
    result = iterator.next();
  }
}

// 启动执行
executeStepByStep();

替代方案:沙箱虚拟机隔离执行

如果需要完全隔离用户代码与游戏主环境,可使用vm2这类沙箱库,在独立虚拟机中运行代码,同时自定义上下文配合生成器实现逐步暂停:

const { VM } = require('vm2');

const vm = new VM({
  sandbox: {
    move: (direction) => {
      return new Promise(resolve => setTimeout(() => {
        console.log(`VM: Moving ${direction}`);
        resolve();
      }, 1000));
    }
  }
});

// 将用户代码转换为生成器后传入沙箱执行
const userGenerator = vm.run(`
  function* userCode() {
    yield move('up');
    yield move('right');
  }
  userCode();
`);

async function runInVM() {
  let iter = userGenerator;
  let result = iter.next();
  while (!result.done) {
    await result.value;
    result = iter.next();
  }
}

runInVM();

关键注意事项

  • 安全性:必须用沙箱隔离用户代码,防止恶意操作游戏核心逻辑,vm2能提供较好的环境隔离能力。
  • AST转换完整性:需处理条件、循环等复杂语句,确保循环内部的每一次迭代也能正确暂停,可能需要优化AST遍历逻辑。
  • 错误处理:捕获生成器执行中的异常,避免崩溃游戏主线程。

内容的提问来源于stack exchange,提问作者inane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:52:24