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

时间:2023-03-08 15:13:43
一步一步实现基于Task的Promise库(四)无参数的WorkItem

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

 (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);
}
}
}
}; var WorkItem = function(arrayArgs){
var _subItems = [];
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]);
}
}
}
var _startSubItem = function(subItemIndex, context){
var subItem = _subItems[subItemIndex];
if(subItem.isFunc){
var workItemCxt = context.getWorkItemContext(subItemIndex);
subItem.func.apply(workItemCxt, subItem.args);
}
else{
if(subItem.task.getStatus() == TaskStatus.finished){
context.end(subItem.task.getOutput(), subItemIndex)
}
else{
subItem.task.finished(function(output){
context.end(output, subItemIndex);
});
subItem.task.start(context.inputParams);
}
}
}; this.condition = "";
this.start = function(context){
context.setItemsCount(_subItems.length);
for(var i=0; i<_subItems.length; i++){
_startSubItem(i, context);
}
}
};
//无参数的WorkItem,用于对前一个WorkItem的条件判断,例如all();
//ConditionWorkItem和WorkItem可以看做实现了一个接口{condition:string,start:function}
var ConditionWorkItem = function(){
this.condition = "";
this.start = function(context){
context.triggerEnd();
}
}; var Context = function(endCallback, inputParams){
var _this = this;
var _rawOutputParams = [];
var _itemCount;
//如果无需Test,_isNonTest就等于true(当调用triggerEnd方法时,就应该无需Test,直接下一个WorkItem)
var _isNonTest = false;
var _condition = {
then: function(){
_this.outputParams = _rawOutputParams[0].value;
return true;
},
all: function(){
_this.outputParams = [];
for(var i=0; i<_itemCount; i++){
if(_rawOutputParams[i]){
_this.outputParams[i] = _rawOutputParams[i].value;
}
else{
return false;
}
}
return true;
},
any: function(){
for(var i=0; i<_itemCount; i++){
if(_rawOutputParams[i]){
_this.outputParams = _rawOutputParams[i].value;
return true;
}
}
return false;
}
}; this.inputParams = inputParams;
this.outputParams = null;
this.setItemsCount = function(itemCount){
_itemCount = itemCount;
};
this.testCondition = function(key){
//如果无需Test直接返回true,否则才用Test
return _isNonTest || _condition[key]();
};
this.end = function(output, index){
_rawOutputParams[index] = {
value: output
};
if(endCallback){
endCallback(output);
}
};
this.getWorkItemContext = function(index){
return {
param: _this.inputParams,
end: function(output){
_this.end(output, index);
}
};
};
//手动触发EndCallback,(这个上下文设置成无需Test,this.outputParams就设置成this.inputParams,这样参数就可以传递到下一个WorkItem了)
this.triggerEnd = function(){
_isNonTest = true;
_this.outputParams = _this.inputParams;
if(endCallback){
endCallback(_this.outputParams);
}
};
}; var TaskStatus = {
//未开始
pending: 0,
//正在进行
doing: 1,
//已完成
finished: 2
}; window.Task = function(){
var _status = TaskStatus.pending;
var _wItemQueue = [], _currentItem, _currentContext;
var _eventManager = new EventManager();
var _output;
var _initWorkItem = function(args){
var item;
if(args.length == 0){
item = new ConditionWorkItem();
}
else{
var arrayArgs = [];
for(var i=0; i<args.length; i++){
arrayArgs[i] = args[i];
}
item = new WorkItem(arrayArgs);
}
_wItemQueue.push(item);
return item;
};
var _setItemCondition = function(item, condition){
if(condition){
item.condition = condition;
}
};
var _tryDoNextItem = function(output){
var next = _getCurNextItem();
if(next){
if(_currentContext.testCondition(next.condition)){
_currentItem = next;
_doCurrentItem();
}
}
else{
_status = TaskStatus.finished;
_output = output;
_eventManager.trigger("finish", output);
}
};
var _doCurrentItem = function(contextParam){
if(contextParam) {
_currentContext = new Context(_tryDoNextItem, contextParam);
}
else{
if(_currentContext){
_currentContext = new Context(_tryDoNextItem, _currentContext.outputParams);
}
else{
_currentContext = new Context(_tryDoNextItem);
}
}
_currentItem.start(_currentContext);
};
var _getCurNextItem = function(){
var i=0;
for(; i<_wItemQueue.length; i++){
if(_currentItem == _wItemQueue[i]){
break;
}
}
return _wItemQueue[i + 1];
};
_currentItem = _initWorkItem(arguments); this.getStatus = function(){
return _status;
};
this.getOutput = function(){
return _output;
};
this.finished = function(callback){
if(callback){
_eventManager.addHandler("finish", callback);
}
};
this.start = function(contextParam){
if(_status == TaskStatus.pending){
_status = TaskStatus.doing;
_doCurrentItem(contextParam);
}
return this;
};
this.then = function(){
var workItem = _initWorkItem(arguments);
_setItemCondition(workItem, 'then');
return this;
};
this.all = function(){
//这个arguments现在可能是空的了!
var workItem = _initWorkItem(arguments);
_setItemCondition(workItem, 'all');
return this;
};
this.any = function(){
var workItem = _initWorkItem(arguments);
_setItemCondition(workItem, 'any');
return this;
};
};
})();
var task = new Task([readFile, "aa.txt"], [readFile, "bb.txt"]).all(writeBack, "cc.txt").start();

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

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

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