该文章阅读需要5分钟,更多文章请点击本人博客halu886
流程控制库
wind
这里还有一种完全不同的异步编程方案wind。前身是jscex,为Javascript提供一种拓展monadic。
以下以一个冒泡进行举例
var compare = function(x,y){
return x-y;
}
var swap = function(a,j,j){
var t = a[i];a[i]=a[j];a[j]= t;
}
var bubbleSort = function(array){
for(var i= 0;i<array.length;i++){
for(var i = 0;i<array.length;i++){
if(compare(array[j],array[j+1]>0)){
swap(array,j,j+1);
}
}
}
};
现在我们要添加一个动画的需求,我们可以在swap()中添加动画的逻辑。但是动画的渲染得是延时的,但是js中延时方法setTimeout()是异步的。那么就会出现以下两个问题。
- 动画执行时无法停止排序算法的执行。
- 排序算法执行会启用更多的动画。
wind在这个问题体现了它的独特魅力。
var compare= function(x,y){
return x-y;
}
var swapAsync = eval(Wind.compile("async",function(a,i,j){
$await(Wind.Async.sleep(20));
var t = a[i];a[i]= a[j];a[j] = t;
paint(a); //重绘数组
}))
var bubbleSort = eval(Wind.compile("async",function(array){
for(var i = 0;i<array.length;i++){
for(var j = 0;j<array.length-i-1;j++){
if(compare(array[j],array[j+1]>0){
$await(swapAsync(array,j,j+1));
})
}
}
}));
以上代码实现了暂停20秒,绘制动画。但是并没有因为引入异步流程库而变得异步化,逻辑并没有因为异步而拆分。
以上代码引入了一些新东西
- eval(Wind.compile(“async”,function(){}));
- $await();
- Wind.Async.sleep(20);
以下我们将详细介绍
异步任务定义
在Wind 中,巧妙的运用了 eval 的访问上下文的特性,Wind.compile() 将function编译,同时Wind.Async.sleep则对setTimeOut进行了封装。
$await()与任务模型
在定义完异步方法后,通过$await等待异步方法结束,但是它只不过是一个等待的占位符,告诉编译器需要到这里等待。
$await的参数一个任务对象,当任务结束后执行后续的操作。任何异步操作都可以转换为任务。wind基于任务模型进行实现的。
以下将fs.readFile()转化为一个任务
var Wind = require("wind");
var Task = Wind.Async.Task;
var readFileAsync = function(file,encoding){
return Task.create(function(t){
fs.readFile(file,encoding,function(err,file){
if(err){
t.complete("failure",err);
}else{
t.complete("success",file);
}
});
});
}
除了使用eval(wind.compile(“async”,function(){}))生成异步任务,标准的异步任务创建方式是Task.create()方式,通过偏函数转换得到真正的任务。当异步完成时通过complete传递failure/success。异常则可以通过try/catch捕获。
例如,调用readFileAsync()得到一个任务
var task = readFileAsync('file1.txt','utf-8');
var serial = eval(Wind.compile("async",function(){
var file1 = $await(readFileAsync('file1.txt','utf-8');
console.log(file1);
var file2 = $await(readFileAsync('file2.txt','utf-8'));
console.log(file2);
try{
var file3 = $await(readFileAsync('file3.txt','utf-8'));
}catch{
console.log(err);
}
}));
serial().start();
// file1
// file2
// { [Error:ENOENT,open 'file3.txt'] errno:34,code:'ENOENT',path:'file3.txt'}
异步通常能够会立即返回,wink做到了不阻塞CPU却阻塞业务代码。
va4 parallel = eval(Wind.compile("async",function(){
var result = $await(Task.whenAll({
file1:readFileAsync('file1.txt','utf-8'),
file2:readFileAsync('file2.txt','utf-8')
}));
console.log(result.file1);
console.log(result.file2);
}));
//file1
//file2
wind配置了Task.whenAll处理并发,通过$await关键字配置当所有任务都完成则向下执行。
异步方法转换为辅助函数
可以看到除了task.compile(“async”,function(){})稍微冗长外,其他的基本基本上和同步方法风格一致。
如同Promise/Deferred模式可以让异步编程模型变得更简单,wind则可以让编程风格同步化,不过我们得提前将异步方法任务化,这也是对Promise/Deferred的封装。
wind提供了两个方法进行辅助转换。
Wind.Async.Binding.fromCallback
Wind.Async.Binding.fromStandard
在Node中,回调传值的方式有两种,一个是没有异常的传递,参数就是异步的结果。
fs.exists("/etc/passwd",function(exists){});
Wind.Async.Binding.fromCallback
就是为转换这一种的。
另一种则是带异常的调用,按照规范第一个参数是异常。
fs.readFile("/etc/passwd",function(err,data){});
Wind.Async.Binding.fromStandard
就是为转换这一种的。
那么readFileAsync则只需要一行代码则可以实现。
以上知识点均来自<<深入浅出Node.js>>,更多细节建议阅读书籍:-)
啥时代了还用eval ? 流控制目前最棒的是 rxjs
@waitingsong 我这是阅读《深入浅出Node.js》的总结,那本书还是14年出版的呢
14年到现在,异步的处理已经翻天覆地了
callback -> fibers -> promise -> async\await
不过了解一下旧的处理方案也不算错,不过你这个库,我确实没听说过
看了一下这个库,已经7年没更新了。。。
@CoderIvan 你搜的哪个 rxjs 哟。。 。 npmjs.org 上面搜 第一个就是 v6.5.2
@CoderIvan 同意, 现在主流基本上是用async/await, 在多个异步并发时配上promise.all基本能解决大部分异步场景, 最主要的是这是ts的语法糖,开箱即用