waitFor和waitForAny的实现

在实现waitFor方法之前,我们先要搞明白下面这些问题:

1. waitFor方法的形参有限制吗?

没有!如果形参是Task类型,不应该启动Task,如果是function类型,会执行方法.所以waitFor的使用场景应该是waitFor(task1,task2),并且task1,2不知道何时启动(比如是用户点击界面按钮来启动)

2. 关于参数的传递。

1 var taskExp_0 = new Task(readFile, "123.txt");
2 var taskExp_1 = new Task(readFile, "aa.txt").start();
3 var taskExp_2 = new Task(readFile, "bb.txt");
4 var taskExp_3 = new Task(taskExp_0).waitFor(taskExp_1, taskExp_2).then(writeFile).start();
5 //taskExp_2模拟不知何时运行的Task,请在控制台运行下面代码
6 //taskExp_2.start();

上面例子中,taskExp_1,taskExp_2不接收taskExp_0的输出参数,我们希望writeFile可以通过this.Param[0],[1],[2]分别接收taskExp_0,taskExp_1,taskExp_2的输出参数。

明确了这样的设计后,下面是Task.js的实现细节和相关demo,有关waitFor和waitForAny的实现请看注释:

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript">
//promise
//读取文件的原始内容
var uploadFile = function (fileName) {
var _this = this;
window.setTimeout(function () {
console.log("uploadFile '" + fileName + "' complete.");
_this.end(fileName);
}, 1800);
};
//读取文件的原始内容
var readFile = function (fileName) {
_fileName = fileName || this.param;
var _this = this;
window.setTimeout(function () {
var rawContent = "xxxxxxxx (" + _fileName + ")";
console.log("read '" + _fileName + "' complete. rawContent is " + rawContent);
_this.end(rawContent);
}, 1000);
};
//请求服务器来解析原始内容,得到真正的内容
var resolveFile = function (serverUrl) {
var _this = this;
var rawContent = _this.param;
window.setTimeout(function () {
var realContent = "Greeting (" + serverUrl + ")";
console.log("resolve file complete. realContent is " + realContent);
_this.end(realContent);
}, 1500);
};
//把真正的内容写入文件
var writeFile = function (fileName) {
var _this = this;
window.setTimeout(function () {
console.log("writeBack1 param[0] is " + _this.param[0] + " ;param[1] is " + _this.param[1]);
_this.end();
}, 2000);
};
var sendMail = function () {
var _this = this;
window.setTimeout(function () {
console.log("sendMail finished");
_this.end();
}, 1000);
};

(function() {
var isFunction = function (target) {
return target instanceof Function;
};
var isArray = function (target) {
return target instanceof Array;
};

//自定义事件管理(代码摘抄自http://www.cnblogs.com/dolphinX/p/3254017.html)
var EventManager = function () {
this.handlers = {};
};
EventManager.prototype = {
constructor: EventManager,
addHandler: function (type, handler) {
if (typeof this.handlers[type] == 'undefined') {
this.handlers[type] = new Array();
}
this.handlers[type].push(handler);
},
removeHandler: function (type, handler) {
if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
for (var i = 0; i < handlers.length; i++) {
if (handler[i] == handler) {
handlers.splice(i, 1);
break;
}
}
}
},
trigger: function (type, event) {
/*
if(!event.target){
event.target = this;
}
*/
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for(var i=0; i<handlers.length; i++){
handlers[i](event);
}
}
}
};

//所有检测条件返回{result: bool, output: obj}
var Condition = {
then: function(target){
return {result: !!target[0], output: target[0].value};
},
all: function(target){
var output = [];
for(var i=0; i<target.length; i++){
if(target[i]){
output.push(target[i].value);
}
else{
return {result: false};
}
}
return {result: true, output: output};
},
any: function(target){
for(var i=0; i<target.length; i++){
if(target[i]){
return {result: true, output: target[i].value};
}
}
return {result: false};
}
};

//option:{
// autoStart: bool, //自动启动
// keepInputParams: bool //是否把上一步传递过来的input传递给它的下一步
//}
//finishedCallback 表示WorkItem满足条件并结束的回调
var WorkItem = function(arrayArgs, finishedCallback, option){
var _subItems = [];
var _rawOutputParams = [];
//完成WorkItem的检测条件
var _condition;
var _input;
option = option || {};
//增加一个bool类型的属性autoStart,默认值为true,表示当调用_startSubItem时是否自动执行subItem(当subItem是task时根据autoStart参数来执行task,如果subItem是方法时,不管autoStart是什么都会执行)
option.autoStart = option.autoStart !== false;
//是否把上一步传递过来的input传递给它的下一步,默认false
option.keepInput = option.keepInput === true;

var _checkFunc = function(args){
if(isFunction(args[0])){
if(args.length == 2 && isArray(args[1])){
_subItems.push({'isFunc': true, 'func': args[0], 'args': args[1]});
}
else{
_subItems.push({'isFunc': true, 'func': args[0], 'args': args.slice(1)});
}
return true;
}
return false;
};
var _checkTask = function(task){
if(task instanceof Task){
_subItems.push({'isFunc': false, 'task': task});
}
};
if(!_checkFunc(arrayArgs)){
for(var i=0; i<arrayArgs.length; i++){
if(!_checkFunc(arrayArgs[i])){
_checkTask(arrayArgs[i]);
}
}
}
_rawOutputParams.length = _subItems.length;

var _startSubItem = function(subItemIndex){
var subItem = _subItems[subItemIndex];
if(subItem.isFunc){
var workItemCxt = _getSubItemContext(subItemIndex);
subItem.func.apply(workItemCxt, subItem.args);
}
else{
if(subItem.task.getStatus() == TaskStatus.finished){
_endSubItem(subItem.task.getOutput(), subItemIndex)
}
else{
subItem.task.finished(function(output){
_endSubItem(output, subItemIndex);
});
if(option.autoStart){
subItem.task.start(_input);
}
}
}
};
var _endSubItem = function(output, index){
_rawOutputParams[index] = {
'value': output
};
var testResult = Condition[_condition](_rawOutputParams);
if(testResult.result){
_onFinishedCallback(testResult.output);
}
};
var _merge = function(target, data){
if(data){
if(isArray(data)){
for(var i=0; i<data.length; i++){
target.push(data[i]);
}
}
else{
target.push(data);
}
}
};
var _onFinishedCallback = function(output){
//如果需要保留输入参数,那么需要对输入和输出参数来一个合并
if(option.keepInput){
var result = [];
_merge(result, _input);
_merge(result, output);
if(result.length == 0){
output = undefined;
}
else{
output = result;
}
}
finishedCallback(output)
};
var _getSubItemContext = function(index){
return {
param: _input,
end: function(output){
_endSubItem(output, index);
}
};
};

this.setCondition = function(condition){
_condition = condition;
};
this.start = function(input){
_input = input;
for(var i=0; i<_subItems.length; i++){
_startSubItem(i);
}
};
};
var ConditionWorkItem = function(finishedCallback){
this.start = function(input){
finishedCallback(input);
};
};

var TaskStatus = {
//未开始
pending: 0,
//正在进行
doing: 1,
//已完成
finished: 2
};

window.Task = function(){
var _status = TaskStatus.pending;
var _wItemQueue = [], _currentItem;
var _eventManager = new EventManager();
var _output;
//设置_wItemQueue队列的最后一个WorkItem的完成条件
var _setLastItemCondition = function(condition){
if(condition != null){
var last = _wItemQueue[_wItemQueue.length - 1];
//因为ConditionWorkItem是没有setCondition方法的(它也不需要判断条件),所以有这个if
if(last.setCondition){
last.setCondition(condition);
}
}
};
var _initWorkItem = function(condition, args, option){
_setLastItemCondition(condition);
var item;
if(args.length == 0){
item = new ConditionWorkItem(_finishCallback);
}
else{
var arrayArgs = [];
for(var i=0; i<args.length; i++){
arrayArgs[i] = args[i];
}
item = new WorkItem(arrayArgs, _finishCallback, option);
}
_wItemQueue.push(item);
return item;
};
//WorkItem完成的回调
var _finishCallback = function(output){
var next = _getCurNextItem();
if(next){
//如果有下一个WorkItem,就start它
_currentItem = next;
_currentItem.start(output);
}
else{
//如果没有就通知Task结束
_status = TaskStatus.finished;
_output = output;
_eventManager.trigger("finish", output);
}
};
var _getCurNextItem = function(){
var i=0;
for(; i<_wItemQueue.length; i++){
if(_currentItem == _wItemQueue[i]){
break;
}
}
return _wItemQueue[i + 1];
};
_currentItem = _initWorkItem(null, arguments);

this.getStatus = function(){
return _status;
};
this.getOutput = function(){
return _output;
};
this.finished = function(callback){
if(callback){
_eventManager.addHandler("finish", callback);
}
};
this.start = function(input){
if(_status == TaskStatus.pending){
_status = TaskStatus.doing;
//start的时候给最后一个WorkItem设置then条件
_setLastItemCondition("then");
_currentItem.start(input);
}
return this;
};
this.waitFor = function(){
//先初始化一个不会自启动的WorkItem,并且这个WorkItem把上一步传递过来的input传递给它的下一步
//进入这个WorkItem的条件是then,如果你想要进入条件是all,可以这样 xxxxx.all().waitFor(task1).xxxxx
_initWorkItem("then", arguments, {autoStart: false, keepInput: true});
//最后调用all()表示这个WorkItem里面的所有子Item必须都完成才能继续下一步
return this.all();
};
this.waitForAny = function(){
_initWorkItem("then", arguments, {autoStart: false, keepInput: true});
//前面和waitFor的逻辑一样,最后调用any()表示这个WorkItem里面的所有子Item完成其中一个就可以进入下一步
return this.any();
};
this.then = function(){
_initWorkItem('then', arguments);
return this;
};
this.all = function(){
_initWorkItem('all', arguments);
return this;
};
this.any = function(){
_initWorkItem('any', arguments);
return this;
};
};
})();

var taskExp_1 = new Task(readFile, "aa.txt").then(resolveFile, "/service/fileResolve.ashx?file=aa.txt");
var taskExp_2 = new Task(uploadFile, "bb.txt").then(readFile, "bb.txt").then(resolveFile, "/service/fileResolve.ashx?file=bb.txt");
var taskExp_3 = new Task(taskExp_1).waitFor(taskExp_2).then(writeFile, ["cc.txt"]).then(sendMail).start();
//taskExp_2模拟不知何时运行的Task,请在控制台运行下面代码
//taskExp_2.start();

</script>
</body>
</html>

 
 
分类: Web前端
标签: Task.js

waitFor和waitForAny的实现的更多相关文章

  1. 一步一步实现基于Task的Promise库(五)waitFor和waitForAny的实现

    在实现waitFor方法之前,我们先要搞明白下面这些问题: 1. waitFor方法的形参有限制吗? 没有!如果形参是Task类型,不应该启动Task,如果是function类型,会执行方法.所以wa ...

  2. distribution 中一直在运行 waitfor delay @strdelaytime 语句

    Replication 自动创建来一个 Job:Replication monitoring refresher for distribution,这个Agent执行一个sp: dbo.sp_repl ...

  3. selenium提供了三种模式的断言:assert,verify,waitfor

    Assert:失败时,该测试将终止 Verify:失败时,该测试继续执行,并将错误日志记录在日显示屏 Waitfor:等待某些条件变为真,一般使用在AJAX应用程序的测试 断言常用的有,具体见如下:a ...

  4. Process的Waitfor() 引起代码死锁

    Java用process调用c#的exe后,process.waitfor(). exe执行会停在某处.据说是waitfor引起的exe子线程死锁. 先存一个链接 http://yearsaaaa12 ...

  5. Delphi中线程类TThread实现多线程编程2---事件、临界区、Synchronize、WaitFor……

    接着上文介绍TThread. 现在开始说明 Synchronize和WaitFor 但是在介绍这两个函数之前,需要先介绍另外两个线程同步技术:事件和临界区 事件(Event) 事件(Event)与De ...

  6. java Process的waitFor()

    java Process的waitFor() 在编写Java程序时,有时候我们需要调用其他的诸如exe,shell这样的程序或脚本.在Java中提供了两种方法来启动其他程序: (1) 使用Runtim ...

  7. sql waitfor 延时执行

    看MSDN:http://msdn.microsoft.com/zh-cn/library/ms187331.aspx 语法为: WAITFOR { DELAY 'time_to_pass' | TI ...

  8. Robotium API -- 等待执行的方法sleep、waitFor

    测试中经常出现明明有控件或者文本,但是由于界面没有载入完成或者其他原因导致assert判断的结果失败.或者两次执行,一次成功,一次失败的情况.所以需要加入这些等待某些控件或者文本载入的方法,以加强程序 ...

  9. mysql定时执行及延时执行,实现类似sql server waitfor功能

    熟悉SQL Server的人都知道,它有一个很有用的功能,waitfor time和waitfor delay,前者表示在某个时间执行,后者表示等待多长时间执行.在我们测试功能和定时执行的时候特别有用 ...

随机推荐

  1. JavaEE(19) - Web层和EJB的整合(Session Bean)

    1. 通过依赖注入访问无状态Session Bean #1. EJB注入Servlet中 #2. EJB注入JSF中 2. 通过EJB引用访问有状态Session Bean 3. 在工具类中访问Ses ...

  2. 彩色图像--色彩空间 HSI(HSL)、HSV(HSB)

    得知DIP文章66日 转载请注明文章出处:http://blog.csdn.net/tonyshengtan ,出于尊重文章作者的劳动,转载请标明出处!文章代码已托管.欢迎共同开发:https://g ...

  3. Android KK台,联系人列表#集团放置A~Z之前

    更改文件ContactLocaleUtils.java两 (Path:packages/contactsprovider/src/com/android/providers/contacts) 1. ...

  4. C++ 虚函数表决心

    C++ 虚函数表解析 xml:namespace prefix = o /> 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制. 关 ...

  5. Codeforces Round #306 (Div. 2) C

    意甲冠军 到不超过一个更100该整数字符串.采取随机从数间(不能拿). 问:是否有可能被剩下8除尽.假设能,出口YES和任选一个数字的其余病例的. 不能够,输出NO. 思路 想法题. 首先观察到.10 ...

  6. [dp] hdu 4472 Count

    意甲冠军: 鉴于n节点,满足子节点的相同的树节点号的同一层较少不同的形式. 思考: dp[i][j] 代表i节点.最后,一个层j方法节点 由于满足同层节点,所以j一层又一层必须是j 整数倍 所以就能得 ...

  7. wcf系列5天速成——第一天 binding的使用(1)

    原文:wcf系列5天速成--第一天 binding的使用(1) 作为WCF速成系列,只介绍些项目开发中常用到的实战知识. 学习wcf,还是对其中的几个术语要了解一下.wcf中有一个ABC的概念,就是 ...

  8. vim添加自己//解决方案

    使用vim从外面将代码复制并粘贴到时间,假设有一排//凝视.自己主动下一行加入//和每行增加一个<tab>.格全乱:其他编辑器*.c *cpp其他文件格当公式,假设有一排//凝视,按o换行 ...

  9. 【Head First Javascript】学习笔记0——自己制作chm参考手册素材

    变量声明:var 常量声明:const 数据格式转换: 1.转换函数 parseInt(A):把字符串A转换成整数:其中A为只包含数字的字符串 parseFloat(A):把字符串A转换成浮点数:其中 ...

  10. CSDN博客频道维护公告

    各位亲爱的用户:        为了给大家提供更稳定的使用环境,2014年4月23日23点至04月24日1点(本周四凌晨)博客频道server将进行维护,维护期间不能正常訪问.给大家带来不便,敬请广大 ...