Javascript JS在生成的函数中等待/暂停 我在做什么 我正在使用Buffy构建一个海龟图形应用程序。用户可以从块构建代码,然后块引擎生成JS代码,并绘制到画布 我的问题是什么

Javascript JS在生成的函数中等待/暂停 我在做什么 我正在使用Buffy构建一个海龟图形应用程序。用户可以从块构建代码,然后块引擎生成JS代码,并绘制到画布 我的问题是什么,javascript,blockly,Javascript,Blockly,Blockly引擎生成JS代码,但将其作为字符串返回,我必须eval()才能将其绘制到画布上 我可以更改块的代码以生成不同的输出,但重要的是要使其尽可能简单,因为用户可以读取块输入后面的实际代码。所以我不想把事情搞砸 我想做什么 我完全控制原子操作(go,turn,等等),因此我想在函数的开头插入一小段代码,这会延迟函数其余部分的执行。比如: function go(dir, dist) { // wait here a little // do the drawing } 我认为它

Blockly引擎生成JS代码,但将其作为字符串返回,我必须
eval()
才能将其绘制到画布上

我可以更改块的代码以生成不同的输出,但重要的是要使其尽可能简单,因为用户可以读取块输入后面的实际代码。所以我不想把事情搞砸

我想做什么 我完全控制原子操作(
go
turn
,等等),因此我想在函数的开头插入一小段代码,这会延迟函数其余部分的执行。比如:

function go(dir, dist) {
  // wait here a little

  // do the drawing
}
我认为它应该是同步的,这样可以保持执行流中的延迟。我尝试使用
setTimeout
(异步,失败),一个
promise
(失败),循环中的时间戳检查(失败)

如果我能理解你的话,在JS中也有可能吗! 您可以构建一个新类来处理执行go(dir,dist)函数,并重写go函数以在executor中创建新的go

function GoExecutor(){

    var executeArray = [];     // Store go methods that waiting for execute
    var isRunning = false;     // Handle looper function

    // start runner function
    var run = function(){
        if(isRunning)
            return;
        isRunning = true;
        runner();
    }

    // looper for executeArray
    var runner = function(){
        if(executeArray.length == 0){
            isRunning = false;
            return;
        }

        // pop the first inserted params 
        var currentExec = executeArray.shift(0);

        // wait delay miliseconds
        setTimeout(function(){
            // execute the original go function
            originalGoFunction(currentExec.dir, currentExec.dist);

            // after finish drawing loop on the next execute method
            runner();
        }, currentExec.delay);

    }
    this.push = function(dir, dist){
        executeArray.push([dir,dist]);
        run();
    }
}

// GoExecutor instance
var goExec = new GoExecutor();

// Override go function
var originalGoFunction = go;
var go = function (dir, dist, delay){
    goExec.push({"dir":dir, "dist":dist, "delay":delay});
}
编辑1: 现在您必须使用函数和参数调用callWithDelay, 执行器将通过将参数应用于指定函数来处理此调用

function GoExecutor(){

    var executeArray = [];     // Store go methods that waiting for execute
    var isRunning = false;     // Handle looper function

    // start runner function
    var run = function(){
        if(isRunning)
            return;
        isRunning = true;
        runner();
    }

    // looper for executeArray
    var runner = function(){
        if(executeArray.length == 0){
            isRunning = false;
            return;
        }

        // pop the first inserted params 
        var currentExec = executeArray.shift(0);

        // wait delay miliseconds
        setTimeout(function(){
            // execute the original go function
            currentExec.funcNam.apply(currentExec.funcNam, currentExec.arrayParams);

            // after finish drawing loop on the next execute method
            runner();
        }, currentExec.delay);

    }
    this.push = function(dir, dist){
        executeArray.push([dir,dist]);
        run();
    }
}

// GoExecutor instance
var goExec = new GoExecutor();

var callWithDelay = function (func, arrayParams, delay){
    goExec.push({"func": func, "arrayParams":arrayParams, "delay":delay});
}

您不能让代码同步等待。你只会得到一个冻结的浏览器窗口

您需要的是使用而不是eval。通过这种方式,您可以暂停执行、播放动画、突出显示当前正在执行的块等。。。本教程有许多示例可以帮助您入门。以下是一个工作代码,基于:

var workspace=Blockly.inject(“编辑器div”{
工具箱:document.getElementById('toolbox')
});
Blockly.JavaScript.STATEMENT_PREFIX='highlightBlock(%1)\n′;
addReservedWords('highlightBlock');
Blockly.JavaScript['text_print']=函数(block){
var argument0=Blockly.JavaScript.valueToCode(
块“文本”,
Blockly.JavaScript.ORDER\函数\调用
) || '\'\'';
返回“打印(“+argument0+”);\n';
};
函数运行(){
var code=Blockly.JavaScript.workspaceToCode(workspace);
var running=false;
traceOn(true);
workspace.highlightBlock(空);
var lastBlockToHighlight=null;
var my解释器=新解释器(代码,(解释器,范围)=>{
解释器.setProperty(
范围“highlightBlock”,
解释器.createNativeFunction(id=>{
id=id?id.toString():“”;
运行=错误;
workspace.highlightBlock(lastBlockToHighlight);
lastBlockToHighlight=id;
})
);
解释器.setProperty(
范围“打印”,
createNativeFunction(val=>{
val=val?val.toString():“”;
控制台日志(val);
})
);
});
var intervalId=setInterval(()=>{
运行=真;
(跑步时){
如果(!my解释器.step()){
workspace.highlightBlock(lastBlockToHighlight);
clearInterval(intervalId);
返回;
}
}
}, 500);
}
#编辑器div{
宽度:500px;
高度:150像素;
}

最近我发布了一个库,允许您与blockly进行异步交互,我为类似的游戏设计了这个库。 事实上,在文档中你可以找到一个游戏演示,它是游戏的翻拍版。

该库名为blockly gamepad,您为什么希望如此延迟?例如,播放一些动画?等待是什么意思?如果你的意思是阻止js执行引擎,那么循环是唯一的方法。你不能延迟同步执行。您必须生成异步代码,但正如我看到的,blocky还没有这样的代码生成器。这没有什么意义,异步变量更难阅读。但是有一个js解释器,你可以用它异步地(安全地)逐行运行代码。如果你使用的环境支持
async/await
,你可以编写看似同步的代码,但最终它必须是异步的。@TamasHegedus它是一个教育应用程序。很高兴能一步一步地看到形状是如何创建的。我来看看。谢谢我可以将一个对象及其所有成员传递给解释器吗?我的所有原子函数都是
turtle
对象的成员。如果可能的话,一次传递所有函数会更容易,而不是一个接一个地传递几十个函数。然而,代码执行非常慢。看起来两个步骤之间的延迟比应该的慢30倍左右。如果我为
setInterval
设置1000ms延迟,则两个步骤之间的延迟约为30s。有什么想法吗?@Nekomajin42:补充了一些improvements@Nekomajin42您可以看到,我有几个函数,它们有不同的名称和参数列表。@Nekomajin42请参见“编辑1”。而且它们的顺序是随机的,因为用户构造的代码是由Blockly生成的。然后您应该使用回调,您提到过“我尝试在循环中使用setTimeout(异步,失败)、承诺(失败)、时间戳检查(失败)“你是如何实现它的?我将坚持@Tamas的解决方案,但我投票支持你,因为它可以帮助其他人。非常感谢。你好,保罗。请你解释一下你的库是如何解决OP所问的问题的。你可以找到它是如何工作的解释@保罗。我的意见是,你应该解释这是如何在SO中工作的,而不是链接到另一个链接可能会消亡的站点。嗨,Mike,链接重定向到github文档,但不应该消亡。现在我修改了答案,让一切都清楚了