2021SC@SDUSC
目录
2.after(name, action, context opt)
3.allSettled (任务)→{ clay.async.TaskGroup }
4.before(name, 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}
15.on(name, action, context opt)
16.once(name, action, context opt)
19.success(action, context opt)
一.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参数来运行,从而实现事件的出发。