一步一步实现基于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,否则才用Test
150             return _isNonTest || _condition[key]();
151         };
152         this.end = function(output, index){
153             _rawOutputParams[index] = {
154                 value: output
155             };
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: 2
185     };
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 //测试1
2 var taskExp_1 = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all().then(writeBack, "cc.txt").start();
3 //测试2
4 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 //测试3
7 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方法。

posted @ 2014-07-26 12:46  lh2907883  阅读(241)  评论(0编辑  收藏  举报