浅谈Jscex的$await语义及异步任务模型
2011-05-10 22:29 by 老赵, 3193 visits从某些程度上说,Jscex的是提供了“新语言”,只不过这种新语言和JavaScript长的一模一样,最多添加了一个$await操作这个语义而已。其他方面,JavaScript的各种语法都可以让Jscex编译,所以它基本可以说是个完备的方案。之前有朋友提出疑问,说$await只能执行单个任务,那么岂不是多个任务之间就出现了先后依赖关系?假如有三个任务:A和B可以并行,但C依赖前两者,ABC如果串行的话,系统的总耗时便不够理想了。其实Jscex并没有这种限制,因为它的任务模型和$await语义简单且具有深厚的理论基础,灵活、丰富而统一。
首先谈下$await的语义,有些朋友阅读示例代码,可能会觉得它表示“执行一个异步任务”。其实不然。$await的语义实际上只是“等待该任务结束”,同时:
- 如果该任务没有运行,则启动该任务。
- 如果该任务已经完成,则立即返回结果(或抛出异常)。
在Jscex的异步类库中,“异步任务”是独立的模型,它有自己的start或addListener等成员。一个Jscex异步函数的执行结果也是个异步任务对象,我们最终也是调用其start方法来启动这个任务。在一个Jscex函数内部,我们也可以手动地启动任务。例如:
function (taskA, taskB, taskC) {
taskA.start();
taskB.start();
$await(taskA);
$await(taskB);
$await(taskC);
}
任务A和B的start方法会在调用后立即返回,并在两者都完成后,才会启动并等待C任务。以上便回答了之前那个朋友提出的问题。由于A和B没有依赖,我们便让其并行执行;C依赖前两者,于是便等A和B结束再启动,仅此而已。事实上,我们也可以这么做:
function (taskA, taskB, taskC) {
$await(Jscex.Async.parallel(taskA, taskB));
$await(taskC);
}
Jscex.Async.parallel是一个辅助函数,接受一堆异步任务,并返回一个新的异步任务,执行它表示并行地执行这些子任务,它也会在子任务都完成后才结束。这个异步任务模型十分简单,人人都能轻松地使用及扩展,也十分灵活。假如我们将刚才的需求换一下:C依赖于B,但A与前两者都独立,则可以编写这样的代码:
function (taskA, taskB, taskC) {
taskA.start();
$await(taskB.continueWith(taskC));
$await(taskA);
}
在JavaScript中,我们只要为Jscex.Async.Task对象扩展一个continueWith方法,表示taskC将于taskB之后执行,并作为一个新任务返回即可。此类Future/Promise模型,以及Jscex的Monadic编译形式在异步编程领域中都有着经典的理论基础,因此Jscex在异步编程方面的支持可谓简单而统一。
Jscex一直在不断前进,如今Jscex又支持了一种$await语句形式,“赋值”:
hello.world = $await(...);
其实按理说,Jscex早该支持这种形式了,但可能是由于最早的思路有些过于借鉴F#的模式(无副作用,因此没有此类赋值),一不留意便疏忽至今了。JavaScript其实终究是一门更为“命令式”的语言,虽然Jscex由F#那里得到启发,但如今其具体实现和最终形式,却也是专为JavaScript而设计的,以确保其必要的功能(例如break,continue等中断逻辑流的语言特性)与性能。
学习并支持一下。语法和调用方式都简洁易懂,但是...现在开发中都还用不上啊。