4. 异常处理
这一节我们讨论异常处理。异常是我们在写代码过程中经常遇到的,我们把一个脚本的崩溃也称作发生异常,这是因为脚本的崩溃会导致后续代码中断执行,导致不可预料到的后果。针对异常我们经常用的方式是去捕获,捕获后清理。我们来看一个例子,服务器玩家执行update。
for(let i = this.tPlayer.length()-1; i >=0; --i){
let oPlayer = this.tPlayer[i];
oPlayer.update();
}
代码的意思就是遍历所有的玩家,执行他们的update函数。但是player的update是可能发生脚本崩溃,为了一个玩家的崩溃不影响到另外的玩家,我们需要加上异常捕获:
for(let i = this.tPlayer.length()-1; i >=0; --i){
try{
let oPlayer = this.tPlayer[i];
oPlayer.update();
}catch{
this.tPlayer.removeAt(i);
}
}
在每个玩家执行update的外部用try包裹住,当发生异常的时候,把玩家移除。关于try catch的效率问题见下面的一个帖子
https://www.zhihu.com/question/29459586
我们这里不去讨论try catch本身是否会存在性能损耗,我们假设try catch是存在损耗的,那么上面的循环就会导致过高的损耗发生,会花费一定的时间,这是无法接受的。接着我们来优化一下,我们还是不能放弃异常处理,但也希望能更加有效率。
let nIndex = this.tPlayer.length()-1;
while(true){
try{
let oPlayer = this.tPlayer[nIndex];
oPlayer.update();
}catch{
this.tPlayer.remove(nIndex);
}
if(--nIndex < 0){
break;
}
}
这是优化过的,这样的实现不仅仅可以保证异常控制在一定范围内,也可以保证效率。
下面我们来看一个简单的异常框架:
let nIndex = 0;
try{
//干第一件事
nIndex = 1;
//干第二件事
nIndex = 2;
//干第三件事
nIndex = 3;
}catch{
swtich(nIndex){
case 0:
break;
case 1:
break;
case 2:
break;
}
}
这段代码主要表达的是,我们可以根据异常的不同阶段,进行不同的清理。比如到第一阶段完成后发生异常需要清理什么,第二阶段后需要清理什么。拿剧情系统举例,如果在某个剧情发生了异常,那么需要把前面剧情创建的对象全部清理掉。
总结下异常的处理,我们需要先划分最小的异常范围,然后在进行少量的异常捕获,在捕获后需要把异常的对象清理掉。这就是整个异常处理的过程。这里需要掌握的是核心的处理方式,就是我们怎么样可安全的处理好一个不确定性能的代码。有时候我们不需要了解到底是否这个代码有耗时什么的,只要优雅的使用代码,像前面的章节说的那样,用我们的思维习惯减少需要了解的知识量,提高代码的稳定程度。