首页 > 代码库 > 一步一步实现基于Task的Promise库(四)无参数的WorkItem

一步一步实现基于Task的Promise库(四)无参数的WorkItem

接着上一篇我直接给出代码,现在支持了new Task(), then(), all(), any() 这些不传参的调用方式。

  1 (function(){  2     var isFunction = function (target) {  3         return target instanceof Function;  4     };  5     var isArray = function (target) {  6         return target instanceof Array;  7     };  8   9     //自定义事件管理(代码摘抄自http://www.cnblogs.com/dolphinX/p/3254017.html) 10     var EventManager = function(){ 11         this.handlers = {}; 12     }; 13     EventManager.prototype = { 14         constructor: EventManager, 15         addHandler: function(type, handler){ 16             if(typeof this.handlers[type] == ‘undefined‘){ 17                 this.handlers[type] = new Array(); 18             } 19             this.handlers[type].push(handler); 20         }, 21         removeHandler: function(type, handler){ 22             if(this.handlers[type] instanceof Array){ 23                 var handlers = this.handlers[type]; 24                 for(var i=0; i<handlers.length; i++){ 25                     if(handler[i] == handler){ 26                         handlers.splice(i, 1); 27                         break; 28                     } 29                 } 30             } 31         }, 32         trigger: function(type, event){ 33             /* 34             if(!event.target){ 35                 event.target = this; 36             } 37             */ 38             if(this.handlers[type] instanceof Array){ 39                 var handlers = this.handlers[type]; 40                 for(var i=0; i<handlers.length; i++){ 41                     handlers[i](event); 42                 } 43             } 44         } 45     }; 46  47     var WorkItem = function(arrayArgs){ 48         var _subItems = []; 49         var _checkFunc = function(args){ 50             if(isFunction(args[0])){ 51                 if(args.length == 2 && isArray(args[1])){ 52                     _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args[1]}); 53                 } 54                 else{ 55                     _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args.slice(1)}); 56                 } 57                 return true; 58             } 59             return false; 60         }; 61         var _checkTask = function(task){ 62             if(task instanceof Task){ 63                 _subItems.push({‘isFunc‘: false, ‘task‘: task}); 64             } 65         }; 66         if(!_checkFunc(arrayArgs)){ 67                 for(var i=0; i<arrayArgs.length; i++){ 68                     if(!_checkFunc(arrayArgs[i])){ 69                         _checkTask(arrayArgs[i]); 70                     } 71                 } 72             } 73         var _startSubItem = function(subItemIndex, context){ 74             var subItem = _subItems[subItemIndex]; 75             if(subItem.isFunc){ 76                 var workItemCxt = context.getWorkItemContext(subItemIndex); 77                 subItem.func.apply(workItemCxt, subItem.args); 78             } 79             else{ 80                 if(subItem.task.getStatus() == TaskStatus.finished){ 81                     context.end(subItem.task.getOutput(), subItemIndex) 82                 } 83                 else{ 84                     subItem.task.finished(function(output){ 85                         context.end(output, subItemIndex); 86                     }); 87                     subItem.task.start(context.inputParams); 88                 } 89             } 90         }; 91  92         this.condition = ""; 93         this.start = function(context){ 94             context.setItemsCount(_subItems.length); 95             for(var i=0; i<_subItems.length; i++){ 96                 _startSubItem(i, context); 97             } 98         } 99     };100     //无参数的WorkItem,用于对前一个WorkItem的条件判断,例如all();101     //ConditionWorkItem和WorkItem可以看做实现了一个接口{condition:string,start:function}102     var ConditionWorkItem = function(){103         this.condition = "";104         this.start = function(context){105             context.triggerEnd();106         }107     };108 109     var Context = function(endCallback, inputParams){110         var _this = this;111         var _rawOutputParams = [];112         var _itemCount;113         //如果无需Test,_isNonTest就等于true(当调用triggerEnd方法时,就应该无需Test,直接下一个WorkItem)114         var _isNonTest = false;115         var _condition = {116             then: function(){117                 _this.outputParams = _rawOutputParams[0].value;118                 return true;119             },120             all: function(){121                 _this.outputParams = [];122                 for(var i=0; i<_itemCount; i++){123                     if(_rawOutputParams[i]){124                         _this.outputParams[i] = _rawOutputParams[i].value;125                     }126                     else{127                         return false;128                     }129                 }130                 return true;131             },132             any: function(){133                 for(var i=0; i<_itemCount; i++){134                     if(_rawOutputParams[i]){135                         _this.outputParams = _rawOutputParams[i].value;136                         return true;137                     }138                 }139                 return false;140             }141         };142 143         this.inputParams = inputParams;144         this.outputParams = null;145         this.setItemsCount = function(itemCount){146             _itemCount = itemCount;147         };148         this.testCondition = function(key){149             //如果无需Test直接返回true,否则才用Test150             return _isNonTest || _condition[key]();151         };152         this.end = function(output, index){153             _rawOutputParams[index] = {154                 value: output155             };156             if(endCallback){157                 endCallback(output);158             }159         };160         this.getWorkItemContext = function(index){161             return {162                 param: _this.inputParams,163                 end: function(output){164                     _this.end(output, index);165                 }166             };167         };168         //手动触发EndCallback,(这个上下文设置成无需Test,this.outputParams就设置成this.inputParams,这样参数就可以传递到下一个WorkItem了)169         this.triggerEnd = function(){170             _isNonTest = true;171             _this.outputParams = _this.inputParams;172             if(endCallback){173                 endCallback(_this.outputParams);174             }175         };176     };177 178     var TaskStatus = {179         //未开始180         pending: 0,181         //正在进行182         doing: 1,183         //已完成184         finished: 2185     };186 187     window.Task = function(){188         var _status = TaskStatus.pending;189         var _wItemQueue = [], _currentItem, _currentContext;190         var _eventManager = new EventManager();191         var _output;192         var _initWorkItem = function(args){193             var item;194             if(args.length == 0){195                 item = new ConditionWorkItem();196             }197             else{198                 var arrayArgs = [];199                 for(var i=0; i<args.length; i++){200                     arrayArgs[i] = args[i];201                 }202                 item = new WorkItem(arrayArgs);203             }204             _wItemQueue.push(item);205             return item;206         };207         var _setItemCondition = function(item, condition){208             if(condition){209                 item.condition = condition;210             }211         };212         var _tryDoNextItem = function(output){213             var next = _getCurNextItem();214             if(next){215                 if(_currentContext.testCondition(next.condition)){216                     _currentItem = next;217                     _doCurrentItem();218                 }219             }220             else{221                 _status = TaskStatus.finished;222                 _output = output;223                 _eventManager.trigger("finish", output);224             }225         };226         var _doCurrentItem = function(contextParam){227             if(contextParam) {228                 _currentContext = new Context(_tryDoNextItem, contextParam);229             }230             else{231                 if(_currentContext){232                     _currentContext = new Context(_tryDoNextItem, _currentContext.outputParams);233                 }234                 else{235                     _currentContext = new Context(_tryDoNextItem);236                 }237             }238             _currentItem.start(_currentContext);239         };240         var _getCurNextItem = function(){241             var i=0;242             for(; i<_wItemQueue.length; i++){243                 if(_currentItem == _wItemQueue[i]){244                     break;245                 }246             }247             return _wItemQueue[i + 1];248         };249         _currentItem = _initWorkItem(arguments);250 251         this.getStatus = function(){252             return _status;253         };254         this.getOutput = function(){255             return _output;256         };257         this.finished = function(callback){258             if(callback){259                 _eventManager.addHandler("finish", callback);260             }261         };262         this.start = function(contextParam){263             if(_status == TaskStatus.pending){264                 _status = TaskStatus.doing;265                 _doCurrentItem(contextParam);266             }267             return this;268         };269         this.then = function(){270             var workItem = _initWorkItem(arguments);271             _setItemCondition(workItem, ‘then‘);272             return this;273         };274         this.all = function(){275             //这个arguments现在可能是空的了!276             var workItem = _initWorkItem(arguments);277             _setItemCondition(workItem, ‘all‘);278             return this;279         };280         this.any = function(){281             var workItem = _initWorkItem(arguments);282             _setItemCondition(workItem, ‘any‘);283             return this;284         };285     };286 })();
View Code
var task = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all(writeBack, "cc.txt").start();

现在上面的调用形式同样可以用下面的代码代替:

1 //测试12 var taskExp_1 = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all().then(writeBack, "cc.txt").start();3 //测试24 var taskExp_2 = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all();5 var taskExp_3 = new Task(taskExp_2).then(writeBack, "cc.txt").start();6 //测试37 var taskExp_4 = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all();8 var taskExp_5 = new Task().then(taskExp_4).then(writeBack, "cc.txt").start();

 在下一篇,我们再来实现waitFor方法。