所以我有一个转换为javascript的DSL语言,但有一个问题,每次运行一个函数时,必须将控件赋予执行环境,该环境将决定是否运行该函数,跳过它,或者终止整个程序。例如,语言中的一段代码可能如下所示。
y = 2*r
value = draw(y)
r = 2
这会转化为类似的东西(可读性增加):
(function(){
ASSIGN(["y"], MUL(NUMBER(2), VAR(["r"])));
ASSIGN(["value"], CALL(["draw"],[VAR(["y"])]));
ASSIGN(["r"], NUMBER(2));
})
现在问题是draw是一个异步函数,它需要时间来绘制这个东西,但javascript会立即执行那些东西,但我不想,并且阻止整个线程没有看起来是个好主意。
我想的解决方案是使用发电机,如果我没有弄错他们的用法
(function* (){
yield START();
ASSIGN(["y"], MUL(NUMBER(2), VAR(["r"])));
ASSIGN(["value"], yield CALL(["draw"],[VAR(["y"])]) );
ASSIGN(["r"], NUMBER(2));
yield DONE();
})
因此执行环境的控制权为:
let app = myApp();
//process does the async stuff
let executor = new Executor(app);
executor.run();
class Executor {
constructor(app){
this.app = app;
this.next();
}
next(value){
this.process(this.app.next(value), this.next);
}
process(function_statment, resume){
//Do the async stuff here
resume('value');
}
}
美丽:3
然而,这并不是当前浏览器最兼容的方法,显然生成器并未得到广泛支持。
作为我的最后一招,我会使用。
(function (EENV){
EENV(START(),function(){
ASSIGN(["y"], MUL(NUMBER(2), VAR(["r"])));
EENV(CALL(["draw"],[VAR(["y"])]), function(value){
ASSIGN(["value"], value);
ASSIGN(["r"], NUMBER(2));
EENV(DONE(),function(){});
});
});
})
但是这种方式更难以理解,即使我使用了事件,它仍然会那样,这将使调试转换器变得困难(检查代码,执行单元测试等等)因为它正在制造这样的回调地狱。
执行环境就像。
myApp(function(statment, callback){
//DO ASYNC STUFF
callback(someValue);
});
您有其他解决方案或想法吗?希望与收益率类似?