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

 //读取文件的原始内容
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. 关于Java和.NET之间的通信问题(JSON)

    前言: 最近项目在某XX领导的所谓指引下,非要转型Java,转就转吧,在转的过程前期是个痛苦期,特别.NET旧有项目和Java新项目需要通信时. 进入主题,Java和.NET之间需要通信,这时媒介很多 ...

  2. [LeetCode] 032. Longest Valid Parentheses (Hard) (C++)

    指数:[LeetCode] Leetcode 指标解释 (C++/Java/Python/Sql) Github: https://github.com/illuz/leetcode 032. Lon ...

  3. Node.js新手教程——怎样实现文件上传功能

    作者:zhanhailiang 日期:2014-11-16 本文将介绍怎样使用Node.js实现文件上传功能. 1. 初始化项目信息:npm init [root@~/wade/nodejs/node ...

  4. Hadoop之——CentOS构造ssh否password登录注意事项

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46388809 前提配置:使用root登录改动配置文件:/etc/ssh/sshd_ ...

  5. C# 你不能调用的问题剪贴板线程

    最近在做一个项目,需要使用线程,并使用剪贴板,头发得到较少的数据在剪贴板上后,现在的孩子线程创建一个子线程,我特别困惑,上网查资料.最后,得到最终的.下面的例子现在将概括解: 第一步: public ...

  6. 1023 Train Problem II(卡特兰数)

    Problem Description As we all know the Train Problem I, the boss of the Ignatius Train Station want ...

  7. EF 增删改查 泛型方法、类

    1.定义泛型类 namespace Crm.Data.Logic.Repository{    public abstract class AbstractRepository<TC, T> ...

  8. 雅居乐在核心产品 &quot;决策&quot;

    2015.6.2 在武汉-- 这是一支谦卑且认真学习,又实实在在做产品的 "产品级敏捷团队". "产品级敏捷团队"--在产品版本号开发的生命周期中.均能共同高效 ...

  9. UML之轻松入门(2)-掌握Junit,让我们的开发更高效

         使用UML不仅能够形象化的表达我们的程序思想,并且能够帮助我们提高程序的质量.一个杂乱无章的程序让维护者望而生畏,其成本也可想而知.在面向程序设计(OOD)中有5条原则是帮助我们设计一个高效 ...

  10. Tomcat剖析(二):一个简单的Servlet服务器

    Tomcat剖析(二):一个简单的Servlet服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三) ...