2021SC@SDUSC山东大学软件学院软件工程应用与实践——claygl(源代码分析8)

2021SC@SDUSC

目录

一.clay.async.TaskGroup类概述

二.clay.async.TaskGroup类的作用

三.clay.async.TaskGroup类源码分析

1.new TaskGroup()

2.after(name, action, context opt)

2.all(tasks)

3.allSettled (任务)→{ clay.async.TaskGroup }

4.before(name, action, context opt)

5.error(action, context opt)

6.getFulfilledNumber(recursiveopt) → {number}

7.getRejectedNumber(recursive opt) → {number}

8.getSettledNumber(recursiveopt) → {number}

9.getTaskNumber(recursiveopt) → {number}

10.has (name, action) → {boolean}

11.isFullfilled () → {boolean}

12.isRejected () → {boolean}

13.isSettled() → {boolean}

14.off(action, context opt)

15.on(name, action, context opt)

16.once(name, action, context opt)

17.reject(err)

18.resolve(data)

19.success(action, context opt)

20.trigger(name)


一.clay.async.TaskGroup类概述

    clay.async.TaskGroup类是Task类的组合,继承自Task类,可对多个Task进行操作

二.clay.async.TaskGroup类的作用

    clay.async.TaskGroup类可进行等待所有任务成功执行,等待所有任务完成,获取所有完成的任务,获取所有成功执行的任务,获取失败的任务,获取所有子任务等行动

三.clay.async.TaskGroup类源码分析

1.new TaskGroup()

    该函数为TaskGroup类的构造函数。

    无参数。

    其源代码如下:

var TaskGroup = function () {
    Task.apply(this, arguments);
    this._tasks = [];
    this._fulfilledNumber = 0;
    this._rejectedNumber = 0;
}

    从源代码中可以看出,该构造函数调用Task类的apply方法,传入TaskGroup对象和arguments参数。同时构造成员变量_tasks,赋值为空数组,_fulfilledNumber,赋值为0,_rejectedNumber,赋值为0。

2.after(name, action, context opt)

    该函数的作用是设置事件触发后的动作,继承自Task。

    参数为name,类型为string,表示事件触发后的动作的名称,action,类型为function,表示事件触发后的动作的函数,context,类型为object,表示事件触发后的动作的内容。

    其源代码为:

after: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        name = 'after' + name;
        return this.on(name, action, context);
    }

    从源代码中可以看出,该函数首先判断name和action是否存在,若其中一个不存在,则直接返回,若存在,则在name前加入字符串‘after’,并调用本对象的on(name, action, context)方法,从而实现事件触发后的动作

2.all(tasks)

    该函数的作用是等待所有给定的任务成功,任务也可以是任何将触发成功和错误事件的通知程序对象。

    其参数为tasks,类型为clay.async.Task的数组,表示等待的给定任务。

    其源代码如下:

TaskGroup.prototype.all = function (tasks) {
    var count = 0;
    var self = this;
    var data = [];
    this._tasks = tasks;
    this._fulfilledNumber = 0;
    this._rejectedNumber = 0;
    util.each(tasks, function (task, idx) {
        if (!task || !task.once) {
            return;
        }
        count++;
        task.once('success', function (res) {
            count--;
            self._fulfilledNumber++;
            // TODO
            // Some tasks like texture, loader are not inherited from task
            // We need to set the states here
            task._fulfilled = true;
            task._rejected = false;
            data[idx] = res;
            if (count === 0) {
                self.resolve(data);
            }
        });
        task.once('error', function () {
            self._rejectedNumber ++;
            task._fulfilled = false;
            task._rejected = true;
            self.reject(task);
        });
    });
    if (count === 0) {
        setTimeout(function () {
            self.resolve(data);
        });
        return this;
    }
    return this;
}

     从源代码中可以看出,该函数首先创建局部变量count,赋值为0,self,赋值为本对象,data,赋值为空数组。然后,将本对象的成员变量_task赋值形参tasks,将_fulfilledNumber赋值0,将_rejectedNumber赋值0.

    然后,通过each方法,对tasks中的每一个task对象进行遍历,若task为null或task的once已经执行一次,则返回。若task未执行,则count自增1,若执行成功调用一次success函数,使count自减1,_fulfilledNumber执行次数自增1,设置该task的完成位_fulfilled为true,表示已经完成,设置task的失败位_rejected为false,表示执行成功。同时将data数组中的第idx个对象设置为res,如果count等于0,则调用resolve方法处理data数组,设置任务成功。

    接着,若执行失败执行一次error方法,是_rejectedNumber自增1,设置完成位为_fulfilled为false,表示为完成执行,设置失败位_rejected为true,表示执行失败,并调用reject方法处理task,设置任务失败。

    最后,若count的值为0,表示任务组中所有任务成功完成,对data调用resolve方法,返回本对象,否则,直接返回本对象。因此,通过该方法,可等待所有给定的任务成功。

3.allSettled (任务)→{ clay.async.TaskGroup }

    该函数的作用是等待所有给定的任务完成,成功或失败。

    其参数为tasks,类型为clay.async.Task的数组,表示等待的给定任务。

    其源代码为:

TaskGroup.prototype.allSettled = function (tasks) {
    var count = 0;
    var self = this;
    var data = [];
    if (tasks.length === 0) {
        setTimeout(function () {
            self.trigger('success', data);
        });
        return this;
    }
    this._tasks = tasks;
    util.each(tasks, function (task, idx) {
        if (!task || !task.once) {
            return;
        }
        count++;
        task.once('success', function (res) {
            count--;
            self._fulfilledNumber++;
            task._fulfilled = true;
            task._rejected = false;
            data[idx] = res;
            if (count === 0) {
                self.resolve(data);
            }
        });
        task.once('error', function (err) {
            count--;
            self._rejectedNumber++;
            task._fulfilled = false;
            task._rejected = true;
            // TODO
            data[idx] = null;
            if (count === 0) {
                self.resolve(data);
            }
        });
    });
    return this;
}

    从源代码中可以看出,该函数首先创建局部变量count,赋值为0,self,赋值为本对象,data,赋值为空数组。然后,将本对象的成员变量_task赋值形参tasks,将_fulfilledNumber赋值0,将_rejectedNumber赋值0.

    然后,通过each方法,对tasks中的每一个task对象进行遍历,若task为null或task的once已经执行一次,则返回。若task未执行,则count自增1,若执行成功调用一次success函数,使count自减1,_fulfilledNumber执行次数自增1,设置该task的完成位_fulfilled为true,表示已经完成,设置task的失败位_rejected为false,表示执行成功。同时将data数组中的第idx个对象设置为res,如果count等于0,则调用resolve方法处理data数组,设置任务成功。

    接着,若执行成功调用一次error函数,使count自减1,_rejectedNumber执行次数自增1,设置该task的完成位_fulfilled为false,表示task未完成,设置task的失败位_rejected为true,表示执行失败。同时将data数组中的第idx个对象设置为null,如果count等于0,则调用resolve方法处理data数组,设置任务失败。

    最后,返回本对象。因此,通过该方法,可等待所有给定的任务执行完成。

4.before(name, action, context opt)

    该函数的作用是设置事件触发前的动作,继承自Task。

    参数为name,类型为string,表示事件触发前的动作的名称,action,类型为function,表示事件触发前的动作的函数,context,类型为object,表示事件触发前的动作的内容。

    其源代码为:

before: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        name = 'before' + name;
        return this.on(name, action, context);
    }

    从源代码中可以看出,该函数首先判断name和action是否存在,若其中一个不存在,则直接返回,若存在,则在name前加入字符串‘before’,并调用本对象的on(name, action, context)方法,从而实现事件触发前的动作。

5.error(action, context opt)

    该函数的作用是设置事件发生错误触发的动作,继承自Task。

    action,类型为function,表示事件发生错误触发的函数,context,类型为object,表示事件发生错误触发的内容。

    其源代码如下:

error: function(action, context) {
        return this.once('error', action, context);
    }

    从源代码中可以看出,该函数直接调用本对象的once方法,name为‘error’,另外两个参数为方法的形参,从而实现错误的处理。

6.getFulfilledNumber(recursiveopt) → {number}

    该函数的作用是获取成功的子任务编号,如果子任务也是任务组,则递归可以为真。

    参数为recursive,类型为boolean,表示是否递归。

    其源代码如下:

TaskGroup.prototype.getFulfilledNumber = function (recursive) {
    if (recursive) {
        var nFulfilled = 0;
        for (var i = 0; i < this._tasks.length; i++) {
            var task = this._tasks[i];
            if (task instanceof TaskGroup) {
                nFulfilled += task.getFulfilledNumber(recursive);
            } else if(task._fulfilled) {
                nFulfilled += 1;
            }
        }
        return nFulfilled;
    } else {
        return this._fulfilledNumber;
    }
}

    从源代码可以看出,首先判断recursive,如果为true,表示存在递归,则初始化局部变量nFulfilled为0,对本对象的_tasks数组进行遍历,取出每一个task,如果task不是TaskGroup,则继续递归,否则判断task的_fulfilled是否为真,即成功执行,是则nFulfilled加1,从而得出总共成功的个数,若无递归,则直接返回本对象_fulfilledNumber,得到成功的执行任务。

7.getRejectedNumber(recursive opt) → {number}

    该函数的作用是获取失败的子任务编号,如果子任务也是任务组,则递归可以为真。

    参数为recursive,类型为boolean,表示是否递归。

    其源代码如下:

TaskGroup.prototype.getRejectedNumber = function (recursive) {
    if (recursive) {
        var nRejected = 0;
        for (var i = 0; i < this._tasks.length; i++) {
            var task = this._tasks[i];
            if (task instanceof TaskGroup) {
                nRejected += task.getRejectedNumber(recursive);
            } else if(task._rejected) {
                nRejected += 1;
            }
        }
        return nRejected;
    } else {
        return this._rejectedNumber;
    }
};

    从源代码可以看出,首先判断recursive,如果为true,表示存在递归,则初始化局部变量nRejected为0,对本对象的_tasks数组进行遍历,取出每一个task,如果task不是TaskGroup,则继续递归,否则判断task的_rejected是否为真,即执行失败,是则nRejected加1,从而得出总共失败的个数,若无递归,则直接返回本对象_RejectedNumber,得到失败的执行任务。

8.getSettledNumber(recursiveopt) → {number}

    该函数的作用是获取完成的子任务编号,如果子任务也是任务组,则递归可以为真。

    参数为recursive,类型为boolean,表示是否递归。

    其源代码如下:

TaskGroup.prototype.getSettledNumber = function (recursive) {
    if (recursive) {
        var nSettled = 0;
        for (var i = 0; i < this._tasks.length; i++) {
            var task = this._tasks[i];
            if (task instanceof TaskGroup) {
                nSettled += task.getSettledNumber(recursive);
            } else if(task._rejected || task._fulfilled) {
                nSettled += 1;
            }
        }
        return nSettled;
    } else {
        return this._fulfilledNumber + this._rejectedNumber;
    }
}

    从源代码可以看出,首先判断recursive,如果为true,表示存在递归,则初始化局部变量nSettled为0,对本对象的_tasks数组进行遍历,取出每一个task,如果task不是TaskGroup,则继续递归,否则判断task的_rejected或_fulfilled是否为真,即执行完成,是则nSettled加1,从而得出总共完成的个数,若无递归,则直接返回本对象_RejectedNumber和_fulfilledNumber的和,得到完成的执行任务。

9.getTaskNumber(recursiveopt) → {number}

    该函数的作用是获取所有子任务编号,如果子任务也是任务组,递归可以为真。

    参数为recursive,类型为boolean,表示是否递归。

    其源代码如下:

TaskGroup.prototype.getTaskNumber = function (recursive) {
    if (recursive) {
        var nTask = 0;
        for (var i = 0; i < this._tasks.length; i++) {
            var task = this._tasks[i];
            if (task instanceof TaskGroup) {
                nTask += task.getTaskNumber(recursive);
            } else {
                nTask += 1;
            }
        }
        return nTask;
    } else {
        return this._tasks.length;
    }
}

    从源代码可以看出,首先判断recursive,如果为true,表示存在递归,则初始化局部变量nTask为0,对本对象的_tasks数组进行遍历,取出每一个task,如果task不是TaskGroup,则继续递归,否则nTask加1,从而得出总个数,若无递归,则直接返回本对象_tasks的length长度,得到全部的任务。

10.has (name, action) → {boolean}

    该函数的作用是判断是否注册事件驱动程序,继承自Task。

    参数为name,类型为string,表示事件的名称,action,类型为function,表示事件执行的方法。

    其源代码如下:

has: function(name, action) {
        var handlers = this.__handlers__;
        if (! handlers ||
            ! handlers[name]) {
            return false;
        }
        var hdls = handlers[name];
        for (var i = 0; i < hdls.length; i++) {
            if (hdls[i].action === action) {
                return true;
            }
        }
    }

    从源代码可以看出,首先将本对象的__handlers__成员变量赋值给新建的对象handlers,判断handlers是否存在和handlers中是否存在name的对象,若其中一个条件不满足,则返回false。接着,将handlers中名为name的对象赋给新变量hdls,对hdls进行遍历,若hdls中某一对象的action与形参的action相同,则返回true,从而判断name对象是否有action方法,进而判断是否注册事件驱动程序。

11.isFullfilled () → {boolean}

    该函数判断任务是否成功,继承自Task。

    无参数。

    其源代码如下:

Task.prototype.isFullfilled = function() {
    return this._fullfilled;
}

    函数返回本对象的_fullfilled成员变量。

12.isRejected () → {boolean}

    该函数判断任务是否失败,继承自Task。

    无参数。

    其源代码如下:

Task.prototype.isRejected = function() {
    return this._rejected;
}

    该函数返回本对象的_rejected成员变量。

13.isSettled() → {boolean}

    该函数判断任务是否完成,即要么失败,要么成功,继承自Task。

    无参数。

    其源代码如下:

Task.prototype.isSettled = function() {
    return this._fullfilled || this._rejected;
}

    该函数返回本对象的_rejected和_fullfilled成员变量的或。

14.off(action, context opt)

    该函数的作用是移除事件监听器,继承自Task。

    参数有action,类型为function,表示所移除事件监听器的动作方法,context,类型为object,表示所移除事件监听器的内容。

    其源代码如下:

off: function(name, action) {
        var handlers = this.__handlers__ || (this.__handlers__={});
        if (!action) {
            handlers[name] = [];
            return;
        }
        if (handlers[name]) {
            var hdls = handlers[name];
            var retains = [];
            for (var i = 0; i < hdls.length; i++) {
                if (action && hdls[i].action !== action) {
                    retains.push(hdls[i]);
                }
            }
            handlers[name] = retains;
        }
        return this;
    }

从源代码中可以看出,off方法接收了name和action这两个形式参数,name表示事件监听器的name,action表示事件监听器的action。首先,若本对象的__handlers__成员变量若不为空,则将其赋值给新创建的局部变量handlers,否则将handlers设置为空字典。

    判断action形参,若action为空,则设置handlers中键为name的值为空数组,并返回。判断handlers,若其键为name的值不为空,即action不为空,则创建局部变量hdls,并将handlers[name]赋值给它。继续创建名为retains的空数组。对hdls进行遍历,若action不为空并且hdls中不存在与action一致的action值,则将hdls中符合该特性的action放入retains数组中,并将retains数组重新赋给handlers中键为name的值,通过这一方法,即可删除本对象中的action方法,从而移除事件监听器。最后返回本对象即可。

15.on(name, action, context opt)

    该函数能够注册事件处理程序,继承自Task。

    参数有name,类型为string,表示事件处理程序的名称,action,类型为function,表示事件处理程序的动作方法,context,类型为object,表示事件处理程序的内容。

    其源代码如下:

on: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        var handlers = this.__handlers__ || (this.__handlers__={});
        if (!handlers[name]) {
            handlers[name] = [];
        }
        else {
            if (this.has(name, action)) {
                return;
            }
        }
        var handler = new Handler(action, context || this);
        handlers[name].push(handler);
        return this;
    }

    从源代码中可以看出,接收的形参有三个,分别为name,action,context,分别表示事件处理程序的名称,动作方法,内容。首先,该函数判断时间处理程序的名称和动作方法是否为空,若其中一个为空,则返回。

    接着,若本对象的__handlers__成员变量若不为空,则将其赋值给新创建的局部变量handlers,否则将handlers设置为空字典。

    然后,判断handlers键为name的值是否为空,如果为空则将其初始化为空数组,否则,调用has函数,判断相应name和action的事件处理程序是否已经存在,若存在则返回。

    最后,采用形参action和context创建一个Handler对象,并赋值给新建的handler局部变量,若context为空,则将本对象作为context。将handler加入到handlers中键为name的数组中即可,从而完成时间处理程序的注册。最后返回本对象。

16.once(name, action, context opt)

    该函数的作用是注册一个事件,该事件仅执行一次便移除,继承自Task。

    参数有name,类型为string,表示事件的名称,action,类型为function,表示事件的动作方法,context,类型为object,表示事件的内容。

    其源代码如下:

once: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        var self = this;
        function wrapper() {
            self.off(name, wrapper);
            action.apply(this, arguments);
        }
        return this.on(name, wrapper, context);
    }

    从源代码中可以看出,接收的形参有三个,分别为name,action,context,分别表示事件处理程序的名称,动作方法,内容。首先,该函数判断时间处理程序的名称和动作方法是否为空,若其中一个为空,则返回。

    接着,创建一个局部变量self,并将本对象赋值给self。执行一个函数wrapper,对self变量调用off方法,移除wrapper事件监听器,接着,通过接收的参数,调用action的apply方法,执行action,从而实现执行该action方法,但执行后即移除该事件,从而实现仅执行一次该方法的作用。最后返回本对象的on函数的返回值,参数为name,wrapper和context。

17.reject(err)

    该函数的作用是设置任务失败,继承自Task。

    参数为err,表示失败事件。

    其源代码如下:

Task.prototype.reject = function(err) {
    this._rejected = true;
    this._fullfilled = false;
    this.trigger('error', err);
}

    由源代码可以看出,该函数设置_rejected为true,表示任务失败,同时设置_fullfilled为false,也表示任务失败,设置标志位为失败后,调用trigger方法,传入参数'error'和err,触发内置的error方法,参数为err。

18.resolve(data)

    该函数的作用是设置任务成功,继承自Task。

    参数为data,表示成功事件。

    其源代码为:

Task.prototype.resolve = function(data) {
    this._fullfilled = true;
    this._rejected = false;
    this.trigger('success', data);
}

    由源代码可以看出,该函数设置_rejected为false,表示任务成功,同时设置_fullfilled为true,也表示任务成功,设置标志位为成功后,调用trigger方法,传入参数'success'和data,触发内置的success方法,参数为data。

19.success(action, context opt)

    该函数的作用是注册success事件处理程序,继承自Task。

    参数为action,类型为function,表示success事件处理程序的动作方法发,context,类型为object,表示success事件处理程序的内容。

    其源代码如下:

success: function(action, context) {
        return this.once('success', action, context);
    }

    从源代码可以看出,该函数调用本对象的once方法,once方法能够注册时间处理程序。传入的参数有name,action和context,name固定为'success',最终实现success事件处理程序的注册。

20.trigger(name)

    该函数的作用是触发事件。

    参数有name,类型为string,表示触发事件的名称,继承自Task。

     其源代码如下:

trigger: function(name) {
        if (!this.hasOwnProperty('__handlers__')) {
            return;
        }
        if (!this.__handlers__.hasOwnProperty(name)) {
            return;
        }
        var hdls = this.__handlers__[name];
        var l = hdls.length, i = -1, args = arguments;
        // Optimize advise from backbone
        switch (args.length) {
            case 1:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context);
                }
                return;
            case 2:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1]);
                }
                return;
            case 3:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2]);
                }
                return;
            case 4:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2], args[3]);
                }
                return;
            case 5:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2], args[3], args[4]);
                }
                return;
            default:
                while (++i < l) {
                    hdls[i].action.apply(hdls[i].context, Array.prototype.slice.call(args, 1));
                }
                return;
        }

    从源代码可以看出,首先判断本对象是否有成员变量__handlers__,若无则返回,若有,则判断__handlers__中是否有键为name的值,若其值为空,则返回。

    若以上两个条件均满足,则创建一个局部变量hdls,将本对象中__handlers__中键为name的值赋给它。获取hdls的长度赋给局部变量l,创建i为-1,args为参数arguments。

    判断args参数的长度,若为1,则调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容;若为2,则调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容和args[1];若为3,则调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容和args[1],args[2];若为4,则调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容和args[1],args[2],args[3];若为5,则调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容和args[1],args[2],args[3],args[4];否则,调用hdls中第一个对象的action方法,参数为hdls第一个对象的内容和所有的args参数。可见,该函数能够调用hdls中的方法,即__handlers__的方法,并以context和arguments参数来运行,从而实现事件的出发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值