一步一步实现基于Task的Promise库(一)Promise的基本实现
如果我们现在有一个需求,大概是先读取一个文件的内容,再把得到的内容传给后台去解析,最后把解析后的结果再保存到那个文件,按照最原始的做法代码就是下面这个样子的:
//读取文件的原始内容
var readFile = function(fileName, callback){
window.setTimeout(function(){
console.log("read '" + fileName + "' complete.");
var rawContent = "..... content ......";
if(callback){
callback(rawContent);
}
}, 2000);
};
//请求服务器来解析原始内容,得到真正的内容
var resolveFile = function(serverUrl, rawContent, callback){
window.setTimeout(function(){
console.log("resolve complete.");
var realContent = "..... 内容 .....";
if(callback){
callback(realContent);
}
}, 1000);
};
//把真正的内容写入一开始的文件
var writeBack = function(fileName, realContent, callback){
window.setTimeout(function(){
console.log("writeBack complete.");
if(callback){
callback();
}
}, 2000);
};
readFile("aa.txt", function(rawContent){
resolveFile("/service/fileResolve.ashx", rawContent, function(realContent){
writeBack("aa.txt", realContent, function(){
//给个完工的通知
alert("everything is ok.");
});
});
});
这里我全部采用window.setTimeout来模拟一个异步操作,然而这种嵌套回调方法的做法看起来非常丑陋,如果能改掉嵌套的形式,采用链式调用会美观很多。因此我们期望的调用形式是下面这个样子:
//期望的调用形式(一) Promise的基本实现
var taskExp1_1 = new Task(readFile, ["aa.txt"])
.then(resolveFile, ["/service/fileResolve.ashx"])
.then(writeBack, ["aa.txt"])
.then(function(){
alert("everything is ok.");
this.end();
})
//do方法才是正真的执行这一组异步调用,不调用do方法相当于只是配置一组异步调用
.do();
这种异步方法的链式调用实际上就是一个Promise的实现,只不过这里是通过一个Task类去完成的,我们的目标就是实现这个Task类,它包含了一组有先后逻辑依赖的异步操作,then方法里面传递的function并不会因为then的执行而执行,实际上then方法可以看做是对一组有先后逻辑依赖的异步操作的一个配置,真正导致执行的是do方法,调用do方法会从这个队列的头部开始调用,而标致一个异步操作的结束是在异步操作方法里面,看下面的代码:
//读取文件的原始内容
var readFile = function(fileName){
var _this = this;
window.setTimeout(function(){
var rawContent = "xxxxxxxx (" + fileName + ")";
console.log("read '" + fileName + "' complete. rawContent is " + rawContent);
//告知异步调用已经完成
_this.end(rawContent);
}, 2000);
};
我们稍微对readFile方法做了修改,当文件读取完成的时候调用this.end方法通知异步操作的完成,这样Task就知道该进行下一个异步操作了,就会执行resolveFile方法,那么这里有一个问题就是readFile方法需要传递一个参数rawContent给resolveFile方法,可以看到this.end(rawContent);这句代码已经有传递,resolveFile方法如何接收呢?
//请求服务器来解析原始内容,得到真正的内容
var resolveFile = function(serverUrl){
var _this = this;
//可以从params属性中获取上一个异步调用传递过来的参数
var rawContent = _this.params;
window.setTimeout(function(){
var realContent = "Greeting (" + serverUrl + ")";
console.log("resolve file complete. realContent is " + realContent);
_this.end(realContent);
}, 1000);
};
可以看到resolveFile方法通过this.params接收readFile的输出参数。
到目前为止,我们看到的都是如何使用Task类,那么我们最希望有一个什么样的库来完成这种逻辑配置关系呢? 除了上面说的传参问题,还有一个就是我希望每一个异步操作都可以接收一些形参,这样我们使用Task类的时候就不用自己拐弯抹角的塞参数了,否则我们可能要这样写:
var taskExp1_1 = new Task(function (){
readFile.call(this, "aa.txt");
}).then(function (){
resolveFile.call(this, "/service/fileResolve.ashx");
}).then(function (){
writeBack.call(this, "aa.txt");
}).then(function () {
alert("everything is ok.");
this.end();
})
.do();
下面是整个demo和Task类的实现细节:
<script type="text/javascript">
//读取文件的原始内容
var readFile = function(fileName){
var _this = this;
window.setTimeout(function(){
var rawContent = "xxxxxxxx (" + fileName + ")";
console.log("read '" + fileName + "' complete. rawContent is " + rawContent);
_this.end(rawContent);
}, 2000);
};
//请求服务器来解析原始内容,得到真正的内容
var resolveFile = function(serverUrl){
var _this = this;
var rawContent = _this.params;
window.setTimeout(function(){
var realContent = "Greeting (" + serverUrl + ")";
console.log("resolve file complete. realContent is " + realContent);
_this.end(realContent);
}, 1000);
};
//把真正的内容写入一开始的文件
var writeBack = function(fileName){
var _this = this;
var realContent = _this.params;
window.setTimeout(function(){
console.log("writeBack complete.");
_this.end();
}, 2000);
};
var WorkItem = function(func, args){
return {
//表示执行此异步操作的先决条件
condition: "",
//表示当前异步操作是否执行完了
isDone: false,
//正真的执行
'do': function(context){
func.call(context, args);
}
};
};
var Task = function(func, args){
//Task内部会维护一个异步方法的队列,此队列严格按照先后顺序执行
var wItemQueue = [];
//当前异步方法
var currentItem;
//执行异步方法前要判断的先决条件集合(目前只有then)
var condition = {
//直接执行
then: function(workItem){
return true;
}
};
//初始化一个异步操作,这个方法主要处理接受参数的多样性
var _initWorkItem = function(func, args, condition){
if(func instanceof Task){
return null;
}
else{
return _enqueueItem(new WorkItem(func, args), condition);
}
};
//记录异步操作的先决条件,并添加到队列中去
var _enqueueItem = function(item, condition){
if(condition){
item.condition = condition;
}
wItemQueue.push(item);
return item;
};
//试着执行下一个异步操作,如果这个操作满足他的先决条件,那就执行
var _tryDoNextItem = function(context){
var next = _getCurNextItem();
if(next){
if(condition[next.condition](next)){
currentItem = next;
currentItem.do(context);
}
}
};
//获取下一个异步操作,如果已经是最后一个了返回undefined
var _getCurNextItem = function(){
var i=0;
for(; i<wItemQueue.length; i++){
if(currentItem == wItemQueue[i]){
break;
}
}
return wItemQueue[i + 1];
};
//定义异步操作的上下文环境
var Context = function(){};
Context.prototype = {
//上一个异步调用传递过来的参数
'params': null,
//执行此方法就表示当前异步操作已经完成,那么会尝试执行下一个异步操作
end: function(output){
currentItem.isDone = true;
this.params = output;
_tryDoNextItem(this);
return this;
}
};
currentItem = _initWorkItem(func, args); //Task的公共方法,这些方法都应该支持链式调用(都返回this)
return {
//开始执行
'do': function(){
if(currentItem && currentItem.condition == ""){
currentItem.do(new Context());
}
return this;
},
//配置下一个异步操作
then: function(func, args){
_initWorkItem(func, args, 'then');
return this;
}
};
}; var taskExp_1 = new Task(readFile, ["aa.txt"])
.then(resolveFile, ["/service/fileResolve.ashx"])
.then(writeBack, ["aa.txt"])
.then(function(){
alert("everything is ok.");
this.end();
})
.do();
</script>
一步一步实现基于Task的Promise库(一)Promise的基本实现的更多相关文章
- 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权
Oauth2授权,熟悉微信开发的同学对这个东西应该不陌生吧.当我们的应用系统需要集成第三方授权时一般都会做oauth集成,今天就来看看在Dapr的语境下我们如何仅通过配置无需修改应用程序的方式让第三方 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定
如果说Actor是dapr有状态服务的内部体现的话,那绑定应该是dapr对serverless这部分的体现了.我们可以通过绑定极大的扩展应用的能力,甚至未来会成为serverless的基础.最开始接触 ...
- 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计
本帖最后由 xinxincaijq 于 2013-1-9 10:27 编辑 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计 转自博客:http:// ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
Dapr提供了一些开箱即用的分布式链路追踪解决方案,今天我们来讲一讲如何通过dapr的configuration来实现非侵入式链路追踪的 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容
上一篇我们讲到了dapr提供的bindings,通过绑定可以让我们的程序轻装上阵,在极端情况下几乎不需要集成任何sdk,仅需要通过httpclient+text.json即可完成对外部组件的调用,这样 ...
随机推荐
- KMP算法之从next[]到nextVal[] (转)
前些日子写了一篇KMP算法的博文,浅谈数据结构之KMP(串中的模式匹配算法),在这片文章中,谈到了一个模式串K值的记录数组 next[],详细可看那篇文章,其实,前面定义的next[]数组是有一定缺陷 ...
- PeopleRank从社交网络中发现个体价值
阅读导读: 1.什么是PeopleRank? 2.PeopleRank和PageRank有什么差别? 3.PR分析微博数据时,怎样对微博单个账号评分? 4.R语言怎样递归计算矩阵特征值? 5.怎样计算 ...
- django csrf_token生成
django模板中生成csrf_token的不同方式 系统环境 CENTOS 6.4 python 2.7.6 django 1.7.1 当post提交表单的的时候,是需要 csrf_token的, ...
- 基于 Android 的 3D 视频样本代码
作者:Mark Liu 下载样本代码 简单介绍 在Android 中,创建一个可以播放视频剪辑的应用很easy:创建一个採用 3D 图形平面的游戏应用也很easy.可是,创建一个可以在 3D 图形对象 ...
- C#-简单的定时器(C# ConsoleApp) ---ShinePans
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc2hpbmVwYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
- 使用ArcGIS API for Silverlight实现地形坡度在线分析
原文:使用ArcGIS API for Silverlight实现地形坡度在线分析 苦逼的研究生课程终于在今天结束了,也许从今以后再也不会坐在大学的课堂上正式的听老师讲课了,接下来的时间就得开始找工作 ...
- div中显示某个网页
原文:div中显示某个网页 1.<iframe>方法 2.ajax方法 ajax+流实现无框架限制块刷新: 主框架index页面: js: $(function(){ $("#d ...
- Atitit.异步编程 java .net php python js 对照
Atitit.异步编程 java .net php python js 的比較 1. 1.异步任务,异步模式, APM模式,, EAP模式, TAP 1 1.1. APM模式: Beg ...
- SQL Server日志文件庞大收缩方法(实测好用)
原文:SQL Server日志文件庞大收缩方法(实测好用) 这两个命令连续执行,间隔时间越少越明显(可多次运行),直到达到效果 --截断 BACKUP LOG CloudMonitor TO DISK ...
- 基于jsoup的Java服务端http(s)代理程序-代理服务器Demo
亲爱的开发者朋友们,知道百度网址翻译么?他们为何能够翻译源网页呢,iframe可是不能跨域操作的哦,那么可以用代理实现.直接上代码: 本Demo基于MVC写的,灰常简单,copy过去,简单改改就可以用 ...