一步一步实现基于Task的Promise库(二)all和any方法的设计和实现

上一篇中我们已经初步完成了Task类,如果仅仅是这些,那么没有多大意义,因为网上这类js库有很多,现在我们来些更复杂的使用场景。

如果我们现在有这样一个需求:我们要先读取aa.txt的内容,然后去后台解析,同时bb.txt也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了。。需求很变态,但是我还是想问有没有好的办法呢?按照最原始的嵌套回调的写法好像不是那么容易了,因为你没法知道aa.txt和bb.txt两个文件的读取解析谁先完成,所以你除了要关注逻辑本身还得花费一些功夫在这个谁先谁后上面,如果需求变了。。。然后就没有然后了,想想我就要吐血。

那么回到上一章的Task类,Task有没有办法解决这个问题呢?回答是有,先看下面的代码:

1 var taskExp_1 = new Task(readFile, ["aa.txt"]).then(resolveFile, ["/service/fileResolve.ashx?file=aa.txt"]);
2 var taskExp_2 = new Task(readFile, ["bb.txt"]).then(resolveFile, ["/service/fileResolve.ashx?file=bb.txt"]);
3 var taskExp_3 = new Task(taskExp_1, taskExp_2).all(writeFile, ["cc.txt"]).then(sendMail).start();

如同需求描述的一样,taskExp_1,taskExp_2分别描述了aa.txt和bb.txt的读取和解析,taskExp_3的构造方法里面包括了taskExp_1,taskExp_2,后面的all方法表示需要taskExp_1和taskExp_2都完成才能执行writeFile,最后才是sendMail。这样一来彻底解决了这类需求带来的复杂性,如果把all改成any表示taskExp_1和taskExp_2完成其中一个就能执行writeFile。

在实现all和any方法之前,先看一看我们将要面临哪些问题:

  1. 现在new Task(),then(),all(),any()方法的形参可以是多个异步操作了,并且每个异步操作可以是一个方法和它的参数,也可以是一个Task。
  2. 既然这些方法的形参可以是Task,那么我们理所当然要支持Task的完成通知。
  3. 一组异步操作的返回值如何传递到下一组异步操作 ,对于all方法如何接收前一组异步操作的所有输出参数呢?在上一章里我们通过this.param接收参数,这里对于then,any方法同样如此,因为最终它们只会有一个异步操作的输出参数传递到下一个异步操作,all方法比较特殊,我斟酌好久决定使用this.param[0],this.param[1]... 来接收同组的不同异步操作的输出参数
  4. 当不同状态的Task作为参数传递到另一个Task中时(未开始执行的,正在执行的,执行完成的),应该怎么处理?我们还得支持Task的状态管理。

继续上一章所写的Task类来扩展这两个方法,现在我们以一个标准的js库形式来书写实现细节,这个库命名为Task.js:

  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     //WorkItem的参数和Task一样,有下面几种形式,不过最终存到subItems里面的元素只有两种类型.一种是方法和它的参数,一种是Task对象
 48     //1.(func, [funcArg1, funcArg2])
 49     //2.(func, funcArg1, funcArg2, ....)
 50     //3.(task1, task2, ....)
 51     //4.([func, funcArg1, funcArg2, ....]
 52     //   ,[func, [funcArg1, funcArg2]]
 53     //   ,task1
 54     //   , ....
 55     //  )
 56     var WorkItem = function(arrayArgs){
 57         //WorkItem其实是一组异步操作的集合,_subItems就是这个集合
 58         var _subItems = [];
 59         var _checkFunc = function(args){
 60             if(isFunction(args[0])){
 61                 if(args.length == 2 && isArray(args[1])){
 62                     _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args[1]});
 63                 }
 64                 else{
 65                     _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args.slice(1)});
 66                 }
 67                 return true;
 68             }
 69             return false;
 70         };
 71         var _checkTask = function(task){
 72             if(task instanceof Task){
 73                 _subItems.push({‘isFunc‘: false, ‘task‘: task});
 74             }
 75         };
 76         //这里是对形参的检测,看看是否满足上面的4种形式
 77         if(!_checkFunc(arrayArgs)){
 78             for(var i=0; i<arrayArgs.length; i++){
 79                 if(!_checkFunc(arrayArgs[i])){
 80                     _checkTask(arrayArgs[i]);
 81                 }
 82             }
 83         }
 84
 85         //开始执行SubItem
 86         var _startSubItem = function(subItemIndex, context){
 87             var subItem = _subItems[subItemIndex];
 88             //如果subItem是方法和它的参数
 89             if(subItem.isFunc){
 90                 //先获取方法的上下文环境(就是方法里面的this)
 91                 var workItemCxt = context.getWorkItemContext(subItemIndex);
 92                 //再执行方法
 93                 subItem.func.apply(workItemCxt, subItem.args);
 94             }
 95             //如果subItem是Task对象
 96             else{
 97                 //如果task已经完成
 98                 if(subItem.task.getStatus() == TaskStatus.finished){
 99                     context.end(subItem.task.getOutput(), subItemIndex)
100                 }
101                 else{
102                     //先注册Task对象的完成事件
103                     subItem.task.finished(function(output){
104                         context.end(output, subItemIndex);
105                     });
106                     //再启动这个task
107                     subItem.task.start(context.inputParams);
108                 }
109             }
110         };
111         this.condition = "";
112         //开始执行WorkItem
113         this.start = function(context){
114             context.setItemsCount(_subItems.length);
115             for(var i=0; i<_subItems.length; i++){
116                 _startSubItem(i, context);
117             }
118         }
119     };
120
121     //异步操作上下文
122     var Context = function(endCallback, inputParams){
123         var _this = this;
124         //Workitem里面的每一个Item会按各自的索引把返回值存到_rawOutputParams里,这样做的目的是为了方便后续操作的先决条件判断
125         var _rawOutputParams = [];
126         //子Item个数
127         var _itemCount;
128         //先决条件的判断方法集合,判断的同时也会更新outputParams
129         var _condition = {
130             then: function(){
131                 _this.outputParams = _rawOutputParams[0].value;
132                 return true;
133             },
134             all: function(){
135                 _this.outputParams = [];
136                 for(var i=0; i<_itemCount; i++){
137                     if(_rawOutputParams[i]){
138                         _this.outputParams[i] = _rawOutputParams[i].value;
139                     }
140                     else{
141                         return false;
142                     }
143                 }
144                 return true;
145             },
146             any: function(){
147                 for(var i=0; i<_itemCount; i++){
148                     if(_rawOutputParams[i]){
149                         _this.outputParams = _rawOutputParams[i].value;
150                         return true;
151                     }
152                 }
153                 return false;
154             }
155         };
156
157         //异步操作的输入操作
158         this.inputParams = inputParams;
159         //最终异步操作上下文结束时的输出参数(一般是一个操作的输出参数,all条件的输出参数比较特殊,是一个数组,每一个元素对应每一个子Workitem的输出参数)
160         this.outputParams = null;
161         this.setItemsCount = function(itemCount){
162             _itemCount = itemCount;
163         };
164         //测试_rawOutputParams对于key条件是否通过
165         this.testCondition = function(key){
166             return _condition[key]();
167         };
168         //索引为index的子Workitem完成时会调用这个方法
169         this.end = function(output, index){
170             _rawOutputParams[index] = {
171                 value: output
172             };
173             if(endCallback){
174                 endCallback(output);
175             }
176         };
177         //生成一个子Workitem执行时的上下文环境
178         this.getWorkItemContext = function(index){
179             //这个是子Item的上下文对象(就是this)
180             return {
181                 //传递给上下文的参数
182                 param: _this.inputParams,
183                 //调用end方法告知异步操作的完成
184                 end: function(output){
185                     _this.end(output, index);
186                 }
187             };
188         };
189     };
190
191     //Task的状态
192     var TaskStatus = {
193         //未开始
194         pending: 0,
195         //正在进行
196         doing: 1,
197         //已完成
198         finished: 2
199     };
200
201     //不定义具体形参,直接使用arguments
202     window.Task = function(){
203         var _status = TaskStatus.pending;
204         var _wItemQueue = [], _currentItem, _currentContext;
205         var _eventManager = new EventManager();
206         var _output;
207         //初始化一个WorkItem,并添加到执行队列中
208         var _initWorkItem = function(args){
209             var arrayArgs = [];
210             for(var i=0; i<args.length; i++){
211                 arrayArgs[i] = args[i];
212             }
213             var item = new WorkItem(arrayArgs);
214             _wItemQueue.push(item);
215             return item;
216         };
217         //设置item的先决条件
218         var _setItemCondition = function(item, condition){
219             if(condition){
220                 item.condition = condition;
221             }
222         };
223         //试着执行下一个异步操作,如果这个操作满足他的先决条件,那就执行;如果已经式最后一个异步操作了,就触发完成事件
224         var _tryDoNextItem = function(output){
225             var next = _getCurNextItem();
226             if(next){
227                 if(_currentContext.testCondition(next.condition)){
228                     _currentItem = next;
229                     _doCurrentItem();
230                 }
231             }
232             else{
233                 _status = TaskStatus.finished;
234                 _output = output;
235                 _eventManager.trigger("finish", output);
236             }
237         };
238         //执行当前的Workitem
239         var _doCurrentItem = function(contextParam){
240             if(contextParam) {
241                 _currentContext = new Context(_tryDoNextItem, contextParam);
242             }
243             else{
244                 if(_currentContext){
245                     _currentContext = new Context(_tryDoNextItem, _currentContext.outputParams);
246                 }
247                 else{
248                     _currentContext = new Context(_tryDoNextItem);
249                 }
250             }
251             _currentItem.start(_currentContext);
252         };
253         //获取下一个异步操作,如果已经是最后一个了返回undefined
254         var _getCurNextItem = function(){
255             var i=0;
256             for(; i<_wItemQueue.length; i++){
257                 if(_currentItem == _wItemQueue[i]){
258                     break;
259                 }
260             }
261             return _wItemQueue[i + 1];
262         };
263         _currentItem = _initWorkItem(arguments);
264
265         //获取Task当前状态
266         this.getStatus = function(){
267             return _status;
268         };
269         //获取Task完成时的输出参数
270         this.getOutput = function(){
271             return _output;
272         };
273         //注册完成事件
274         this.finished = function(callback){
275             if(callback){
276                 _eventManager.addHandler("finish", callback);
277             }
278         };
279         //任务开始(把do改成start是因为在ie下有问题,ie会把do当做保留字)
280         //contextParam是一个上下文参数,可以在异步方法中通过this.Param引用
281         this.start = function(contextParam){
282             if(_status == TaskStatus.pending){
283                 _status = TaskStatus.doing;
284                 _doCurrentItem(contextParam);
285             }
286             return this;
287         };
288         this.then = function(){
289             var workItem = _initWorkItem(arguments);
290             _setItemCondition(workItem, ‘then‘);
291             return this;
292         };
293         this.all = function(){
294             var workItem = _initWorkItem(arguments);
295             _setItemCondition(workItem, ‘all‘);
296             return this;
297         };
298         this.any = function(){
299             var workItem = _initWorkItem(arguments);
300             _setItemCondition(workItem, ‘any‘);
301             return this;
302         };
303     };
304 })();

除了之前的Task类之外,还添加了WorkItem类用来表示一组异步操作。代码有点多,细节请看注释。

最后给一个demo:

  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4     <title></title>
  5 </head>
  6 <body>
  7     <script src="jquery-latest.js" type="text/javascript"></script>
  8     <script type="text/javascript">
  9         //promise
 10         //读取文件的原始内容
 11         var readFile = function(fileName){
 12             var _this = this;
 13             window.setTimeout(function(){
 14                 var rawContent = "xxxxxxxx (" + fileName + ")";
 15                 console.log("read ‘" + fileName + "‘ complete. rawContent is " + rawContent);
 16                 _this.end(rawContent);
 17             }, 1000);
 18         };
 19         //请求服务器来解析原始内容,得到真正的内容
 20         var resolveFile = function(serverUrl){
 21             var _this = this;
 22             var rawContent = _this.param;
 23             window.setTimeout(function(){
 24                 var realContent = "Greeting (" + serverUrl + ")";
 25                 console.log("resolve file complete. realContent is " + realContent);
 26                 _this.end(realContent);
 27             }, 1500);
 28         };
 29         //把真正的内容写入一开始的文件
 30         var writeFile = function (fileName) {
 31             var _this = this;
 32             window.setTimeout(function(){
 33                 console.log("writeBack1 param[0] is " + _this.param[0] + " ;param[1] is " + _this.param[1]);
 34                 _this.end();
 35             }, 2000);
 36         };
 37         var sendMail = function(){
 38             var _this = this;
 39             window.setTimeout(function(){
 40                 console.log("sendMail finished");
 41                 _this.end();
 42             }, 1000);
 43         };
 44
 45         //问题:
 46         //1.WorkItem的参数多样化 (一些没有意义的使用形式?)
 47         //2.new Task(),then,all,any方法参数可以接收Task对象 (Task完成的事件通知?)
 48         //3.一组异步操作的返回值如何传递到下一组异步操作 (对于all方法如何接收前一组异步操作的所有输出参数)
 49         //4.当不同状态的Task作为参数传递到另一个Task中时(未开始执行的,正在执行的,执行完成的),应该怎么处理 (Task状态管理)
 50         (function(){
 51             var isFunction = function(target){
 52                 return target instanceof Function;
 53             };
 54             var isArray = function(target){
 55                 return target instanceof Array;
 56             };
 57
 58             //自定义事件管理(代码摘抄自http://www.cnblogs.com/dolphinX/p/3254017.html)
 59             var EventManager = function(){
 60                 this.handlers = {};
 61             };
 62             EventManager.prototype = {
 63                 constructor: EventManager,
 64                 addHandler: function(type, handler){
 65                     if(typeof this.handlers[type] == ‘undefined‘){
 66                         this.handlers[type] = new Array();
 67                     }
 68                     this.handlers[type].push(handler);
 69                 },
 70                 removeHandler: function(type, handler){
 71                     if(this.handlers[type] instanceof Array){
 72                         var handlers = this.handlers[type];
 73                         for(var i=0; i<handlers.length; i++){
 74                             if(handler[i] == handler){
 75                                 handlers.splice(i, 1);
 76                                 break;
 77                             }
 78                         }
 79                     }
 80                 },
 81                 trigger: function(type, event){
 82                     /*
 83                     if(!event.target){
 84                         event.target = this;
 85                     }
 86                     */
 87                     if(this.handlers[type] instanceof Array){
 88                         var handlers = this.handlers[type];
 89                         for(var i=0; i<handlers.length; i++){
 90                             handlers[i](event);
 91                         }
 92                     }
 93                 }
 94             };
 95
 96             //WorkItem的参数和Task一样,有下面几种形式,不过最终存到subItems里面的元素只有两种类型.一种是方法和它的参数,一种是Task对象
 97             //1.(func, [funcArg1, funcArg2])
 98             //2.(func, funcArg1, funcArg2, ....)
 99             //3.(task1, task2, ....)
100             //4.([func, funcArg1, funcArg2, ....]
101             //   ,[func, [funcArg1, funcArg2]]
102             //   ,task1
103             //   , ....
104             //  )
105             var WorkItem = function(arrayArgs){
106                 //WorkItem其实是一组异步操作的集合,_subItems就是这个集合
107                 var _subItems = [];
108                 var _checkFunc = function(args){
109                     if(isFunction(args[0])){
110                         if(args.length == 2 && isArray(args[1])){
111                             _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args[1]});
112                         }
113                         else{
114                             _subItems.push({‘isFunc‘: true, ‘func‘: args[0], ‘args‘: args.slice(1)});
115                         }
116                         return true;
117                     }
118                     return false;
119                 };
120                 var _checkTask = function(task){
121                     if(task instanceof Task){
122                         _subItems.push({‘isFunc‘: false, ‘task‘: task});
123                     }
124                 };
125                 //这里是对形参的检测,看看是否满足上面的4种形式
126                 if(!_checkFunc(arrayArgs)){
127                     for(var i=0; i<arrayArgs.length; i++){
128                         if(!_checkFunc(arrayArgs[i])){
129                             _checkTask(arrayArgs[i]);
130                         }
131                     }
132                 }
133
134                 //开始执行SubItem
135                 var _startSubItem = function(subItemIndex, context){
136                     var subItem = _subItems[subItemIndex];
137                     //如果subItem是方法和它的参数
138                     if(subItem.isFunc){
139                         //先获取方法的上下文环境(就是方法里面的this)
140                         var workItemCxt = context.getWorkItemContext(subItemIndex);
141                         //再执行方法
142                         subItem.func.apply(workItemCxt, subItem.args);
143                     }
144                     //如果subItem是Task对象
145                     else{
146                         //如果task已经完成
147                         if(subItem.task.getStatus() == TaskStatus.finished){
148                             context.end(subItem.task.getOutput(), subItemIndex)
149                         }
150                         else{
151                             //先注册Task对象的完成事件
152                             subItem.task.finished(function(output){
153                                 context.end(output, subItemIndex);
154                             });
155                             //再启动这个task
156                             subItem.task.start(context.inputParams);
157                         }
158                     }
159                 };
160                 this.condition = "";
161                 //开始执行WorkItem
162                 this.start = function(context){
163                     context.setItemsCount(_subItems.length);
164                     for(var i=0; i<_subItems.length; i++){
165                         _startSubItem(i, context);
166                     }
167                 }
168             };
169
170             //异步操作上下文
171             var Context = function(endCallback, inputParams){
172                 var _this = this;
173                 //Workitem里面的每一个Item会按各自的索引把返回值存到_rawOutputParams里,这样做的目的是为了方便后续操作的先决条件判断
174                 var _rawOutputParams = [];
175                 //子Item个数
176                 var _itemCount;
177                 //先决条件的判断方法集合,判断的同时也会更新outputParams
178                 var _condition = {
179                     then: function(){
180                         _this.outputParams = _rawOutputParams[0].value;
181                         return true;
182                     },
183                     all: function(){
184                         _this.outputParams = [];
185                         for(var i=0; i<_itemCount; i++){
186                             if(_rawOutputParams[i]){
187                                 _this.outputParams[i] = _rawOutputParams[i].value;
188                             }
189                             else{
190                                 return false;
191                             }
192                         }
193                         return true;
194                     },
195                     any: function(){
196                         for(var i=0; i<_itemCount; i++){
197                             if(_rawOutputParams[i]){
198                                 _this.outputParams = _rawOutputParams[i].value;
199                                 return true;
200                             }
201                         }
202                         return false;
203                     }
204                 };
205
206                 //异步操作的输入操作
207                 this.inputParams = inputParams;
208                 //最终异步操作上下文结束时的输出参数(一般是一个操作的输出参数,all条件的输出参数比较特殊,是一个数组,每一个元素对应每一个子Workitem的输出参数)
209                 this.outputParams = null;
210                 this.setItemsCount = function(itemCount){
211                     _itemCount = itemCount;
212                 };
213                 //测试_rawOutputParams对于key条件是否通过
214                 this.testCondition = function(key){
215                     return _condition[key]();
216                 };
217                 //索引为index的子Workitem完成时会调用这个方法
218                 this.end = function(output, index){
219                     _rawOutputParams[index] = {
220                         value: output
221                     };
222                     if(endCallback){
223                         endCallback(output);
224                     }
225                 };
226                 //生成一个子Workitem执行时的上下文环境
227                 this.getWorkItemContext = function(index){
228                     //这个是子Item的上下文对象(就是this)
229                     return {
230                         //传递给上下文的参数
231                         param: _this.inputParams,
232                         //调用end方法告知异步操作的完成
233                         end: function(output){
234                             _this.end(output, index);
235                         }
236                     };
237                 };
238             };
239
240             //Task的状态
241             var TaskStatus = {
242                 //未开始
243                 pending: 0,
244                 //正在进行
245                 doing: 1,
246                 //已完成
247                 finished: 2
248             };
249
250             //不定义具体形参,直接使用arguments
251             window.Task = function(){
252                 var _status = TaskStatus.pending;
253                 var _wItemQueue = [], _currentItem, _currentContext;
254                 var _eventManager = new EventManager();
255                 var _output;
256                 //初始化一个WorkItem,并添加到执行队列中
257                 var _initWorkItem = function(args){
258                     var arrayArgs = [];
259                     for(var i=0; i<args.length; i++){
260                         arrayArgs[i] = args[i];
261                     }
262                     var item = new WorkItem(arrayArgs);
263                     _wItemQueue.push(item);
264                     return item;
265                 };
266                 //设置item的先决条件
267                 var _setItemCondition = function(item, condition){
268                     if(condition){
269                         item.condition = condition;
270                     }
271                 };
272                 //试着执行下一个异步操作,如果这个操作满足他的先决条件,那就执行;如果已经式最后一个异步操作了,就触发完成事件
273                 var _tryDoNextItem = function(output){
274                     var next = _getCurNextItem();
275                     if(next){
276                         if(_currentContext.testCondition(next.condition)){
277                             _currentItem = next;
278                             _doCurrentItem();
279                         }
280                     }
281                     else{
282                         _status = TaskStatus.finished;
283                         _output = output;
284                         _eventManager.trigger("finish", output);
285                     }
286                 };
287                 //执行当前的Workitem
288                 var _doCurrentItem = function(contextParam){
289                     if(contextParam) {
290                         _currentContext = new Context(_tryDoNextItem, contextParam);
291                     }
292                     else{
293                         if(_currentContext){
294                             _currentContext = new Context(_tryDoNextItem, _currentContext.outputParams);
295                         }
296                         else{
297                             _currentContext = new Context(_tryDoNextItem);
298                         }
299                     }
300                     _currentItem.start(_currentContext);
301                 };
302                 //获取下一个异步操作,如果已经是最后一个了返回undefined
303                 var _getCurNextItem = function(){
304                     var i=0;
305                     for(; i<_wItemQueue.length; i++){
306                         if(_currentItem == _wItemQueue[i]){
307                             break;
308                         }
309                     }
310                     return _wItemQueue[i + 1];
311                 };
312                 _currentItem = _initWorkItem(arguments);
313
314                 //获取Task当前状态
315                 this.getStatus = function(){
316                     return _status;
317                 };
318                 //获取Task完成时的输出参数
319                 this.getOutput = function(){
320                     return _output;
321                 };
322                 //注册完成事件
323                 this.finished = function(callback){
324                     if(callback){
325                         _eventManager.addHandler("finish", callback);
326                     }
327                 };
328                 //任务开始(把do改成start是因为在ie下有问题,ie会把do当做保留字)
329                 //contextParam是一个上下文参数,可以在异步方法中通过this.Param引用
330                 this.start = function(contextParam){
331                     if(_status == TaskStatus.pending){
332                         _status = TaskStatus.doing;
333                         _doCurrentItem(contextParam);
334                     }
335                     return this;
336                 };
337                 this.then = function(){
338                     var workItem = _initWorkItem(arguments);
339                     _setItemCondition(workItem, ‘then‘);
340                     return this;
341                 };
342                 this.all = function(){
343                     var workItem = _initWorkItem(arguments);
344                     _setItemCondition(workItem, ‘all‘);
345                     return this;
346                 };
347                 this.any = function(){
348                     var workItem = _initWorkItem(arguments);
349                     _setItemCondition(workItem, ‘any‘);
350                     return this;
351                 };
352             };
353         })();
354
355
356         var taskExp_1 = new Task(readFile, ["aa.txt"]).then(resolveFile, ["/service/fileResolve.ashx?file=aa.txt"]);
357         var taskExp_2 = new Task(readFile, ["bb.txt"]).then(resolveFile, ["/service/fileResolve.ashx?file=bb.txt"]);
358         var taskExp_3 = new Task(taskExp_1, taskExp_2).all(writeFile, ["cc.txt"]).then(sendMail).start();
359
360     </script>
361 </body>
362 </html>

一步一步实现基于Task的Promise库(二)all和any方法的设计和实现

时间: 2024-11-03 21:23:40

一步一步实现基于Task的Promise库(二)all和any方法的设计和实现的相关文章

一步一步实现基于Task的Promise库(三)waitFor方法的设计

在上一篇中我们已经完成了Task.js里面的all和any方法,已经可以完美的解决大部分需求,我们再来看一个需求: 我们要先读取aa.txt的内容,然后去后台解析,同时由用户指定一个文件,也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了.. 这里的用户是指真正浏览网页的用户,可能是说让用户上传一个文件去读取解析,但是aa.txt是程序定好了的,我们也不希望用户上传文件之后再去读取解析aa.txt,怎么办?如果有一个waitFor方法可以等待另

一步一步实现基于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 //自定义事件管理(代码

一步一步实现基于Task的Promise库(一)Promise的基本实现

如果我们现在有一个需求,大概是先读取一个文件的内容,再把得到的内容传给后台去解析,最后把解析后的结果再保存到那个文件,按照最原始的做法代码就是下面这个样子的: 1 //读取文件的原始内容 2 var readFile = function(fileName, callback){ 3 window.setTimeout(function(){ 4 console.log("read '" + fileName + "' complete."); 5 var rawC

一步一步实现基于Task的Promise库(五)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 =

实现基于Task的异步模式

返回该系列目录<基于Task的异步模式--全面介绍> 生成方法 编译器生成 在.NET Framework 4.5中,C#编译器实现了TAP.任何标有async关键字的方法都是异步方法,编译器会使用TAP执行必要的转换从而异步地实现方法.这样的方法应该返回Task或者Task<TResult>类型.在后者的案例中,方法体应该返回一个TResult,且编译器将确保通过返回的Task<TResult>是可利用的.相似地,方法体内未经处理的异常会被封送到输出的task,造成返

一步一步教你搭建基于docker的MongoDB复制集群环境

一步一步教你搭建基于docker的MongoDB复制集群环境 1.安装docker 2.创建MongoDB的Image 3.搭建MongoDB的集群 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中. 1.ubuntu14.04安装docker 参考文档 http://docs.docker.com/installation/ubuntulinux/ 参考文档 http://docs.docker.com/mac/started/ pc@pc-Th

一步一步实现基于GPU的pathtracer(一):基础

出于3D计算机图形学和图形渲染方面的个人兴趣,脑子里便萌生出了自己实现一个渲染器的想法,主要是借助pathtracing这种简单的算法,外加GPU加速来实现,同时也希望感兴趣的朋友们能够喜欢,也欢迎提出一些更好的看法~~. (本人水平有限,若有错误也请指正~) 首先列个提纲......: 1)局部光照与全局光照简介 2)GPU并行运算在图形渲染的应用 ————————————————————————————————————————————————— 1)pathtracing算法简介: 在利用计

一步一步学习SignalR进行实时通信_2_Persistent Connections

原文:一步一步学习SignalR进行实时通信_2_Persistent Connections 一步一步学习SignalR进行实时通信\_2_Persistent Connections SignalR 一步一步学习SignalR进行实时通信_2_Persistent Connections 前言 安装 Persistent Connections 映射并配置持久连接 结束语 参考文献 前言 上一篇文章简单的介绍了下SignalR,从此篇文章就开始对SignalR进行剖析.在介绍Persiste

一步一步学习Vue(十一)

本篇继续学习vuex,还是以实例为主:我们以一步一步学Vue(四)中讲述的例子为基础,对其改造,基于vuex重构一遍,这是原始的代码: todolist.js ; (function () { var list = []; var Todo = (function () { var id = 1; return function (title, desc) { this.title = title; this.desc = desc; this.id = id++; } })(); /** *