从早期从事基于java的服务器端开发,再到之后从事基于web和js的ui开发,总体感觉基于web页面的ui开发远不如服务器端健壮。主要是早期ie浏览器功能太弱小,很多业务被迫放到服务器端去实现,浏览器端技术设计的比较简单。其次,js这门语言对于异常里也不够完善,没有一套足够完善的异常处理思路,尽管js存在throw、try、catch这种异常的语法,但是js本身是一门函数式编程的语言,try、catch在很多回调场景中是那么无力。

所以一直以来我就想构建出一个完善的js异常处理机制,而且还要基于具体ui实际需求,做出具体的处理逻辑。简单来说,当boss问我们做这种统一的异常处理有什么好处时,作为前端工程师,最理想的回答就是增加用户体验,作为前段工程师,用户体验是我们最大的价值,因为只有增加用户体验,公司才能留住用户,保持盈利,我们才能发挥出价值。那么如何提升用户体验呢?当用户遇到了不同的错误情况,使用最适合的提示方式提供给用户,不就是增加了用户的使用体验吗?

所以统一的异常处理的目的就是,能够使用简单、严谨的思路让程序员开发出更容易维护的代码,增加前端js代码的健壮性,同时将异常处理的提示具体实现和业务逻辑解耦,由统一的提示接口去将处理异常信息。

那么这我们提出设计方案之前,先来分析一下传统的异常处理方法,以及js中使用时候的问题,也来想想为什么我们平时在js中使用异常处理的情况是那么少。

1.责任链模式的异常处理理论

传统的异常处理理论,就是一个责任链模式,当方法A调用方法B,方法B调用方法C,其中每一个方法其实都可能抛出异常,可能处理异常。

function f(){
try{
} catch(e){
//什么也不做
throw e;
}
} //等效于
function f(){}

本身方法调用就是一个链,而异常处理则处于这个链上。当一个方法抛出一个异常时,他本也是异常的第一个接收人(catch到异常),如果是他职责身份能处理的异常,他就应该立刻处理此异常,不再向上抛出;否则就应该向上抛出,抛到上一层方法。依次类推,直到抛到最顶层。通常这个最顶层是一个用户或者系统调用接口,这个接口作为方法调用的发起者,同时也应该是异常处理的最终响应者,在这一层我们将真正地去处理底层方法无法处理的异常。

如何判断一个异常是一个方法能否处理的呢?依据“最小知道原则”和“职责单一原则”,一个异常如果属于其业务范围内的一部分,就应该处理这个异常,如果需要外界知晓这个异常存在,就应该将这个异常加工后抛到上一层。

function fa(){
try{
fb();
}catch(e){
if(e == "方法a能处理的异常"){
console.log("方法a处理了异常")
} else {
console.log("方法a无法处理此异常,继续向上抛出")
throw e;
}
}
}
function fb(){
try{
fc();
}catch(e){
if(e == "方法b能处理的异常"){
console.log("方法b处理了异常")
} else {
console.log("方法b无法处理此异常,继续向上抛出")
throw e;
}
}
}
function fc(){
try{
throw "方法acb都不能处理此异常";
//throw "方法a能处理的异常";
//throw "方法b能处理的异常";
//throw "方法c能处理的异常";
}catch(e){
if(e == "方法c能处理的异常"){
console.log("方法c处理了异常")
} else {
console.log("方法c无法处理此异常,继续向上抛出")
throw e;
}
}
} (function(){
try{
fa()
}catch(e){
console.log("最顶层处理了此异常");
}
})()

其中a、b、c中如果没有可以处理的异常,try、catch语句是可以省略掉的,这样代码就会简写为

function fa(){
fb();
}
function fb(){
fc();
}
function fc(){
throw "方法acb都不能处理此异常";
} (function(){
try{
fa()
}catch(e){
console.log("最顶层处理了此异常");
}
})()

是不是简单了不少,我们实际开发中更多的是这种例子,因为一个函数出现错误,后续执行都将无法正常进行,所以是需要向上层抛出的。因此js语法中的异常处理策略简化了整个过程。

所以说,传统的异常处理就是一个责任链模式。然而js中真的就可以使用这种责任链模式的异常处理吗?为什么我们在开发js中,很少采用这种责任链模式的异常处理呢?接下来我们继续介绍js的异步调用。

2.js异步调用的异常处理

js是个很神奇的语言,用这个语言你可以像用c语言那样在全局变量里,面向过程地编写你的代码,也可以像使用java那种,面向对象地编写代码,他还可以使用现状渐渐开始火起来在函数式的方法编写代码。

在js里面,函数可以向变量一样被声明,可以做方法的入参,可以做方法的返回值,这些都是js不可或缺的语法特性。

因为js还有没有语法级的阻塞方案,这样你无法同步两个不同的线程能够同步彼此,例如一个异步请求,或者调用。当调用一个异步方法,因为没有语法级的阻塞方式,所以整个调用过程中,你无法顺序地编写调用过程,唯一能做的事情只有回调。

这些语法特性使得我们开发的时候,只能做到基于函数回调情况去处理不同的状况,而责任链模式的异常处理也变得不再适用。

function f(){
throw "error";
} try{
setTimeout(f)
} catch(e){
console.log(e) //接收不到这个error的
}

这种情况在实际开发中会经常遇到。最常见的就是一个ajax的异步请求,除此之外,异步io的api、地理定位的api、摄像机的api,这些都是异步的。再比如我们模拟一个alert方法,不使用系统的alert而是我们自己的alert(系统的alert函数调用后会弹出真正的模式对话框,此时线程挂起,运行阻塞,当用户点掉alert对话框后线程才会唤起)。与系统alert不一样,我们自己做的alert只能在回调里加alert后续的业务方法。

//使用Window对象的alert
alert("我被阻塞了");
console.log("执行完毕"); var myAlert = {
show: function(fn) {
//绘制alert对话框略 //监听用户点击事件,点击后回调fn函数
var body = document.querySelector("body");
var _fn = function() {
//去除对话框略
body.removeEventListener("click", _fn)
fn && fn();
}
body.addEventListener("click", _fn, false);
}
} //调用自定义的alert
myAlert.show(function() {
console.log("执行完毕");
})

这种回调在js程序设计中常常被用到,因为这种方式是不支持责任链模式的,所以try、catch这种异常处理的语法在这种调用中很少会被使用到。那么这种基于回调的调用过程,一般使用什么方法做异常处理呢?通常函数本身会有一个错误的回调入参,参数要求是一个我们还是使用a、b、c这三个方法彼此调用来说明。

function fa(error){
var errorFn = function(e){
if(e == "方法a能处理的异常"){
console.log("方法a处理了异常")
} else {
console.log("方法a无法处理此异常,继续向上抛出")
error && error(e);
}
} setTimeout(function(){
fb(errorFn);
})
}
function fb(error){
var errorFn = function(e){
if(e == "方法b能处理的异常"){
console.log("方法b处理了异常")
} else {
console.log("方法b无法处理此异常,继续向上抛出")
error && error(e);
}
} setTimeout(function(){
fc(errorFn);
})
}
function fc(error){
var errorFn = function(e){
if(e == "方法c能处理的异常"){
console.log("方法c处理了异常")
} else {
console.log("方法c无法处理此异常,继续向上抛出")
error && error(e);
}
} setTimeout(function(){
try{
throw "方法acb都不能处理此异常";
//throw "方法a能处理的异常";
//throw "方法b能处理的异常";
//throw "方法c能处理的异常";
}catch(e){
errorFn(e);
}
})
} fa(function(){
  console.log("最顶层处理了此异常");
})

注意这里的errorFn是不可以省略的,因为这个责任链模式是我们手动书写出来的。所以要想实现异步过程的责任链模式,是必须通过自己手动完成的,js并没有提供什么语法糖帮我们简化这个过程(其实也是有的)。

而且,只有最里层的fc当中使用try、catch语句,fb、fa都无法再使用try、catch语句了,因为一旦使用了这种回调方案,就再也无法回归传统的try、catch处理了,这也是try、catch语法无法在js里面流行的一大原因。

这里基本分析出了传统js代码在异常处理方面的方案和出现的问题,如何更好地解决异常处理问题,提供我们程序的健壮性我们值得进一步思考,待续。。。。

js构建ui的统一异常处理方案(一)的更多相关文章

  1. js构建ui的统一异常处理方案(三)

    笔者之前分析了如何实现js的责任链异常处理的方法,通过promise这个异步模型,我们能够对同步方法和异步方法的两种情况,均可以实现责任链模式.有了这些武器,我们就可以开始设计ui的统一异常处理方案了 ...

  2. js构建ui的统一异常处理方案(四)

    上一篇我们介绍了统一异常处理方案的设计方案,这一篇我们将直接做一个小例子,验证我们的设计方案. 例子是一个todo的列表界面(页面代码参考于https://github.com/zongxiao/Dj ...

  3. js构建ui的统一异常处理方案(二)

    上一篇文章,我分析了同步代码做异常处理是基于责任链模式,而通过try.catch等语句可以很容易地实现这种责任链模式.但是如果是异步调用,我们无法直接通过try.catch语句实现责任链模式,并且通过 ...

  4. Spring Boot统一异常处理方案示例

    一.异常处理的原则 1.调用方法的时候返回布尔值来代替返回null,这样可以 NullPointerException.由于空指针是java异常里最恶心的异常. 2. catch块里别不写代码.空ca ...

  5. 【Spring Boot】Spring Boot之统一异常处理

    一.统一异常处理的作用 在web应用中,请求处理时,出现异常是非常常见的.所以当应用出现各类异常时,进行异常的统一捕获或者二次处理(比如空指针异常或sql异常正常是不能外抛)是非常必要的,然后右统一异 ...

  6. Java springmvc 统一异常处理的方案

    前言:为什么要统一异常处理?经常在项目中需要统一处理异常,将异常封装转给前端.也有时需要在项目中统一处理异常后,记录异常日志,做一下统一处理. Springmvc 异常统一处理的方式有三种. 一.使用 ...

  7. 使用webpack+vue.js构建前端工程化

    参考文章:https://blog.csdn.net/qq_40208605/article/details/80661572 使用webpack+vue.js构建前端工程化本篇主要介绍三块知识点: ...

  8. JS构建多端应用

    JS构建多端应用 一,需求与介绍 1.1,介绍 1,Taro 是一套遵循 React语法规范的 多端开发 解决方案.现如今市面上端的形态多种多样,Web.React-Native.微信小程序等各种端大 ...

  9. 【异常处理】Springboot对Controller层方法进行统一异常处理

    Controller层方法,进行统一异常处理 提供两种不同的方案,如下: 方案1:使用 @@ControllerAdvice (或@RestControllerAdvice), @ExceptionH ...

随机推荐

  1. xamarin 学习

    http://www.cnblogs.com/lonelyxmas/p/5174934.html http://www.cnblogs.com/phytan/p/xamarincrack2.html ...

  2. Delphi中stringlist分割字符串的用法

    Delphi中stringlist分割字符串的用法 TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 1.CommaT ...

  3. Microsoft .NET Framework 4.0.3版下载

    适用于 Microsoft .NET Framework 4 的更新 4.0.3,其中包含一系列新增功能,用于满足高端客户的功能需求和重要 .NET Framework 方案的需求. http://w ...

  4. TaintDroid剖析之Native方法级污点跟踪分析

    1.Native方法的污点传播 在前两篇文章中我们详细分析了TaintDroid对DVM栈帧的修改,以及它是如何在修改之后的栈帧中实现DVM变量级污点跟踪的.现在我们继续分析其第二个粒度的污点跟踪—— ...

  5. 在C#代码中应用Log4Net(二)典型的使用方式

    不管用什么框架,学什么东西,最初的想法还不是尽快地用上这个框架,所以我们在这个章节还是不打算介绍具体配置节的应用,而是直接给出一个经典的使用样例,让你尽快上手.即使你对Log4Net的配置不熟悉也完全 ...

  6. Apache Mina实战

    Mina介绍 Mina可以用于快速的开发基于网络通信的应用,特别是在开发手机端的游戏应用时,使用的较为普遍.本文简单介绍了一个用Mina搭建的一个简易讨论组,通过该应用可以对Mina的基本用法用途有个 ...

  7. maven仓库信息分析站点推荐

    maven是java的一个依赖,打包管理的工具,稍微大一点的java项目都需要使用maven. 随着java的壮大,maven仓库越来越大,仓库中的jar包有60多万,各种group,各种构件,各种版 ...

  8. C语言 · 回文数 · 基础练习

    问题描述 1221是一个非常特殊的数,它从左边读和从右边读是一样的,编程求所有这样的四位十进制数. 输出格式 按从小到大的顺序输出满足条件的四位十进制数.   代码如下: 注意:这里要提醒一下读者:蓝 ...

  9. 过段时间逐步使用HTML5新增的web worker等内容

    想来快2017年了,2013年前的手机应该很少有人用了,以后逐渐使用HTML5新增的高级API吧. 先把web worker的内容再熟悉一下,因为微软虚拟学院的'面向有经验开发人员的 JavaScri ...

  10. 我所理解的Cocos2d-x

    我所理解的Cocos2d-x(完全基于Cocos2d-x3.0,深度剖析计算机图形学,OpenGL ES及游戏引擎架构,全面提升游戏开发相关知识) 秦春林 著   ISBN 978-7-121-246 ...