Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 569|回复: 0

angular代码分析之异常日志设计

[复制链接]
  • TA的每日心情
    奋斗
    7 天前
  • 签到天数: 745 天

    [LV.9]以坛为家II

    2041

    主题

    2099

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    704660
    发表于 2021-8-30 14:09:53 | 显示全部楼层 |阅读模式

    angular代码分析之异常日志设计

    错误异常是面向对象开发中的记录提示程序执行问题的一种重要机制,在程序执行发生问题的条件下,异常会在中断程序执行,同时会沿着代码的执行路径一步一步的向上抛出异常,最终会由顶层抛出异常信息。而与异常同时出现的往往是日志,而日志往往需要记录具体发生异常的模块、编码、详细的错误信息、执行堆栈等,方便问题的快速定位分析。angularjs作为前端的框架,其对异常信息的处理是怎样的呢?

    一、定义模块和异常类型

    首先每个模块的日志模块编码是一样的,只需要本模块负责初始化一次即可。通过以下代码我们可以看到angular通过minErr函数传入module参数,并在返回的闭包函数中引用module参数实现这一点。

    //构造模块异常类,module为模块编码,ErrorConstructor异常构造函数
    
    function minErr(module, ErrorConstructor) {
    
    //如果未传入异常构造函数则使用Error
    
    ErrorConstructor = ErrorConstructor || Error;
    
    //返回异常对象构建方法
    
    return function() {
    
     
    
    };
    
    }

    这里需要注意的是传入参数ErrorConstructor,这里可以传入特定类型的异常类,比如ES6内置了RangeErrorReferenceErrorSyntaxErrorTypeErrorURIError异常类型,这样我们就可以实现抛出特定类型的异常。但是我感觉这里不好的一点是无法实现模块内自由灵活的抛出不同的特定类型异常,其实这点可以在闭包函数参数中实现。

    二、定义日志编码和日志信息模板

    当我们每次记录日志的时候,需要传入日志编码及日志信息模板,方便记录异常发生的代码块及更具可读性的异常信息。通过以下的代码,我们可以看到angular通过闭包函数的可变参数的第一个参数定义日志编码,通过第二个参数定义日志信息模板。

    //构造模块异常类,module为模块编码,ErrorConstructor异常构造函数
    
    function minErr(module, ErrorConstructor) {
    
    //如果未传入异常构造函数则使用Error
    
    ErrorConstructor = ErrorConstructor || Error;
    
    //返回异常对象构建方法,传入参数可变
    
    return function() {
    
    //日志编码,只能是第一个参数
    
    var code = arguments[0],
    
    //构造日志前缀
    
    prefix = '[' + (module ? module + ':' : '') + code + '] ',
    
    //日志模板
    
    template = arguments[1],
    
    //传入参数
    
    templateArgs = arguments,
    
    };
    
    }

    三、日志模板信息替换

    通过传入日志相关对象来替换日志模板中的信息,从而形成更有意义的异常信息。通过以下代码我们可以看到angular通过replace方法实现日志模板中站位符的替换。

    //模板信息替换
    
    message = prefix + template.replace(/\{\d+\}/g, function(match) {
    
    //获取站位符的索引,并转化为数字
    
    var index = +match.slice(1, -1), arg;
    
    //获取替换站位符的传入参数对象的字符串表示形式
    
    if (index + 2 < templateArgs.length) {
    
    //对象转换为字符串
    
    return toDebugString(templateArgs[index + 2]);
    
    }
    
    return match;
    
    });

     

    在这里很巧妙的使用了stringreplace方法,通过其正则表达式参数和生成替换字符串的方法实现模板中所有站位符的替换。replace的方法定义如下

    stringObject.replace(regexp/substr,replacement)

    参数

    描述

    regexp/substr

    必需。规定子字符串或要替换的模式的RegExp 对象。

    请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为RegExp 对象。

    replacement

    必需。一个字符串值。规定了替换文本或生成替换文本的函数。


     

     

     

     

     

     

    replacement方法里很巧妙的使用了stringslice方法,实现获取站位符索引。这里使用了两个技巧,其中的+号实现了字符串转化为数字,其中slice中传入的参数1-1巧妙的提取了站位索引。slice的方法定义如下

    stringObject.slice(start,end)

    参数

    描述

    start

    要抽取的片断的起始下标。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。

    end

    紧接着要抽取的片段的结尾的下标。若未指定此参数,则要提取的子串包括start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。

     

     

     

     

     

     

    angular将传入的对象转化为便于调试的字符串形式,具体代码如下,其中函数对象会清空函数体,undefined变量直接返回undefined字符串,字符串则直接返回,其他类型对象则调用serializeObject进行序列化。这里需要注意对函数对象的处理,对匿名函数的处理并不尽如人意,这里我也没有想到更好的处理方式。

    //将传入的对象转化为便于调试的字符串形式
    
    function toDebugString(obj) {
    
    //如果是函数则清空函数体
    
    if (typeof obj === 'function') {
    
    return obj.toString().replace(/ \{[\s\S]*$/, '');
    
    } else if (typeof obj === 'undefined') {
    
    return 'undefined';
    
    } else if (typeof obj !== 'string') {//如果是非字符串的其他对象则进行序列化
    
    return serializeObject(obj);
    
    }
    
    return obj;
    
    }

     

    angular将对象转化为json字符串的代码如下,其通过JSONstringify方法的第二个方法参数控制键值对的序列化结果,同时也通过seen数组防止引用闭环导致序列化死循环。

    //将对象转化为json字符串
    
    function serializeObject(obj) {
    
    var seen = [];
    
    
    return JSON.stringify(obj, function(key, val) {
    
    //获取val的具体字符串表示形式
    
    val = toJsonReplacer(key, val);
    
    //防止引用闭环导致死循环
    
    if (isObject(val)) {
    
    
    if (seen.indexOf(val) >= 0) return '<<already seen>>';
    
    
    seen.push(val);
    
    }
    
    return val;
    
    });
    
    }

     

    JSON.stringify的方法定义如下

    JSON.stringify(value[, replacer[, space]])

    参数

    描述

    value

    待序列化为JSON字符串的对象

    replacer

    可传入数组定义序列化需要包含的属性,或者传入修改序列化行为的方法,如果不传入参数,则默认序列化所有的非方法属性。

    space

    分割符,具体参考以下

    A String or Number object that's used to insert white space into the output JSON string for readability purposes. If this is a Number, it indicates the number of space characters to use as white space; this number is capped at 10 if it's larger than that. Values less than 1 indicate that no space should be used. If this is a String, the string (or the first 10 characters of the string, if it's longer than that) is used as white space. If this parameter is not provided (or is null), no white space is used.



     

     

     

     

     

     

     

     

     

    angular针对内置一些复杂对象的序列化处理代码如下

    //过滤对angular复杂对象的序列化
    
    function toJsonReplacer(key, value) {
    
    var val = value;
    
    //两个$$开头的字符串返回undefined
    
    if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
    
    val = undefined;
    
    } else if (isWindow(value)) {//window
    
    val = '$WINDOW';
    
    } else if (value && document === value) {//document
    
    val = '$DOCUMENT';
    
    } else if (isScope(value)) {//scope
    
    val = '$SCOPE';
    
    }
    
    
    return val;
    
    }

    四、构建在线错误链接

    针对特定的异常能够提供在线解决方案是十分人性化的,angular默认提供跳转到angular的在线错误页面,我们可以根据实际需要替换为我们的。这里直接返回异常实例,方便调用者直接调用函数使用。

    //构建错误在线链接
    
    message = message + '\nhttp://errors.angularjs.org/1.3.9-local+sha.a3c3bf3/' +
    
    (module ? module + '/' : '') + code;
    
    for (i = 2; i < arguments.length; i++) {
    
    message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
    
    encodeURIComponent(toDebugString(arguments));
    
    }
    
    //构建异常错误实例
    
    return new ErrorConstructor(message);

     

    五、整个处理流程如下图所示



     

     

     

     

     

     

     

     

     

     

     

     

     

     

    六、实际使用样例

    调用代码如下

    var codeartistminErr = minErr("CodeRrtist");
    
    throw codeartistminErr("AngularExceptionDesinBlog",'this is my AngularExceptionDesinBlog,{0}',{name:'codeartist'});

    调用结果



     

    添加注释的angular.js源代码文件下载地址 


    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-3-29 00:43 , Processed in 0.080355 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表