zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    外校培训前三节课知识集合纲要(我才不会告诉你我前两节只是单纯的忘了)
    floyd算法----牛栏
    bfs开始--马的遍历
    (DP 线性DP 递推) leetcode 64. Minimum Path Sum
    (DP 线性DP 递推) leetcode 63. Unique Paths II
    (DP 线性DP 递推) leetcode 62. Unique Paths
    (DP 背包) leetcode 198. House Robber
    (贪心 复习) leetcode 1007. Minimum Domino Rotations For Equal Row
    (贪心) leetcode 452. Minimum Number of Arrows to Burst Balloons
    (字符串 栈) leetcode 921. Minimum Add to Make Parentheses Valid
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3871702.html
Copyright © 2011-2022 走看看