• waitFor和waitForAny的实现


    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的实现请看注释:

     View Code

    <!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
  • 相关阅读:
    java进程自动杀死
    线程池的取值(一)与拒绝策略
    zju 1383 Binary Numbers
    可以连续几行数,,,分别相加求和
    几个数字的和
    zju 2812 Quicksum---------hdu 2734
    rwkj 1332 C语言实验四(函数):题目1、数字根
    zju 1295 Reverse Text
    zju 1241 Geometry Made Simple
    hdu 1379 DNA Sorting
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3871702.html
Copyright © 2020-2023  润新知