如果我们现在有一个需求,大概是先读取一个文件的内容,再把得到的内容传给后台去解析,最后把解析后的结果再保存到那个文件,按照最原始的做法代码就是下面这个样子的:

 //读取文件的原始内容
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的基本实现的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理

    状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...

  2. 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务

    我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...

  3. 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流

    在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接 ...

  4. 通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权

    Oauth2授权,熟悉微信开发的同学对这个东西应该不陌生吧.当我们的应用系统需要集成第三方授权时一般都会做oauth集成,今天就来看看在Dapr的语境下我们如何仅通过配置无需修改应用程序的方式让第三方 ...

  5. 通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定

    如果说Actor是dapr有状态服务的内部体现的话,那绑定应该是dapr对serverless这部分的体现了.我们可以通过绑定极大的扩展应用的能力,甚至未来会成为serverless的基础.最开始接触 ...

  6. 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计

    本帖最后由 xinxincaijq 于 2013-1-9 10:27 编辑 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计 转自博客:http:// ...

  7. 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布

    之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...

  8. 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr

    目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...

  9. 通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪

    Dapr提供了一些开箱即用的分布式链路追踪解决方案,今天我们来讲一讲如何通过dapr的configuration来实现非侵入式链路追踪的 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系 ...

  10. 通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容

    上一篇我们讲到了dapr提供的bindings,通过绑定可以让我们的程序轻装上阵,在极端情况下几乎不需要集成任何sdk,仅需要通过httpclient+text.json即可完成对外部组件的调用,这样 ...

随机推荐

  1. Swift: 打造滑动解锁文字动画

    原文:Swift: 打造滑动解锁文字动画 最近木事,找出来玩了玩facebook的paper.到处都是那个"slide to unlock your phone"的效果啊.忽闪忽闪 ...

  2. RabbitMQ (两)工作队列

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/37620057 本系列教程主要来自于官网新手教程的翻译,然后自己进行了部分的改动与 ...

  3. tmp1

    program1: Line # Mem usage Increment Line Contents================================================ 2 ...

  4. XStream 用法汇总

            XStream是一家Java对象和XML转换工具,很好很强大.它提供了所有的基本型.排列.收集和其他类型的支持,直接转换.因此XML在数据交换经常使用.对象序列化(和Java对象的序列 ...

  5. Android利用网络编程HttpClient批量上传(两)AsyncTask+HttpClient监测进展情况,并上传

    请尊重别人的劳动.转载请注明出处: Android网络编程之使用HttpClient批量上传文件(二)AsyncTask+HttpClient并实现上传进度监听 执行效果图: 我曾在<Andro ...

  6. Skype发布视频API

    原文:Skype发布视频API 相信很多人对Skype多少都应该有一些了解,如果以前没有使用过它的服务的话,也应该在最近的新闻中听说过它的大名.因为,它和我们每天都在接触的公司--Mircrosoft ...

  7. 注册 集 与 删除 -- C

    文章3位设置和清除操作. #include <stdio.h> #include <stdlib.h> #include <string.h> #define BI ...

  8. RPC框架

    RPC框架实现 - 路由控制篇 2015-04-27 22:26 by bangerlee, 499 阅读, 1 评论, 收藏, 编辑 RPC(Remote Procedure Call,远程过程调用 ...

  9. 数据结构与算法之递推算法 C++与PHP实现

    数据结构是算法实现的基础,算法总是要依赖于某种数据结构来实现的.往往是在发展一种算法的时候,构建了适合于这样的算法的数据结构.一种数据结构假设脱离了算法,也就没有存在的价值了. 算法的作用----解决 ...

  10. Linux-常用命令1---对文件进行查看、复制、移动和分割

    基于Linux的操作系统是一种自由和开放源代码的类UNIX操作系统. Linux的几大特点决定了它的不可代替和无法超越性: (1)免费的/开源的:(2)支持多线程/多用户: (3)安全性好; (4)对 ...