前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RxDB 异常机制

RxDB 异常机制

作者头像
阿宝哥
发布2019-11-05 15:49:58
1.2K0
发布2019-11-05 15:49:58
举报
文章被收录于专栏:全栈修仙之路

RxDB 是一个由 JavaScript 实现,拥有响应式,离线优先等特性的数据库。它拥有以下特性:

  • 多平台支持:浏览器、Node.js、Electron、Cordova、React-Native 和其它 JavaScript 运行时;
  • 基于 RxJS 的响应式数据处理;
  • 支持客户端与服务端之间的数据备份,兼容 PouchDB,CouchDB 和 IBM Cloudant;
  • 基于易于学习的 jsonschema 标准;
  • 提供 mongoDB 和 mongoose 类似的查询方式;
  • 支持单个字段的加密,从而保护用户的隐私;
  • 支持导入/导入 JSON 数据,非常适合 TDD
  • 支持不同浏览器窗口或 Node.js 进程之间数据同步;
  • 支持 ORM。

接下来本文将基于 RxDB 的 7.5.1 版本,简单分析一下 RxDB 内部的异常机制。

基础知识

JavaScript 异常类型:

  • EvalError —— 创建一个error实例,表示错误的原因:与 eval() 有关。
  • InternalError —— 创建一个代表Javascript引擎内部错误的异常抛出的实例。 如: “递归太多”。
  • RangeError —— 创建一个error实例,表示错误的原因:数值变量或参数超出其有效范围。
  • ReferenceError —— 创建一个error实例,表示错误的原因:无效引用。
  • SyntaxError —— 创建一个error实例,表示错误的原因:eval()在解析代码的过程中发生的语法错误。
  • TypeError —— 创建一个error实例,表示错误的原因:变量或参数不属于有效类型。
  • URIError —— 创建一个error实例,表示错误的原因:给 encodeURI()decodeURl()传递的参数无效。

异常对象分类

在 RxDB 内部主要定义了两个异常类:

  • RxError:继承于 Error 类
  • RxTypeError:继承于 TypeError 类

利用 rx-error.js 文件提供的 newRxError 和 newRxTypeError 方法,我们可以方便地抛出自定义异常。在 encryption 插件内部,若数据库字段加密的密码的长度不为字符串或长度小于 8 时,则会抛出对应的异常。

具体的示例如下:

代码语言:javascript
复制
export const overwritable = {
    validatePassword: function(password) {
        if (password && typeof password !== 'string') {
            throw RxError.newRxTypeError('EN1', {
                password
            });
        }
        if (password && password.length < minPassLength) {
            throw RxError.newRxError('EN2', {
                minPassLength,
                password
            });
        }
    }
};

newRxTypeError 函数

这里我们先来分析 RxError.newRxTypeError:

代码语言:javascript
复制
export const newRxTypeError = (code, parameters) => 
  new RxTypeError(code, overwritable.tunnelErrorMessage(code), parameters);

其中 RxTypeError 继承于 TypeError,该类的实现如下:

代码语言:javascript
复制
/* 
 * TypeError(类型错误)对象用来表示值的类型非预期类型时发生的错误。
 * new TypeError([message[, fileName[, lineNumber]]])
 * message:错误描述
 * fileName:引起该异常代码所在的文件的名字
 * lineNumber:引起该异常的代码的行号
 */
export class RxTypeError extends TypeError {
    // 'EN1', { password }
    constructor(code, message, parameters = {}) {
        const mes = messageForError(message, parameters);
        super(mes);
        this.code = code;
        this.message = mes;
        this.parameters = parameters;
        this.rxdb = true; // tag them as internal
    }
    get name() {
        return 'RxError';
    }
    toString() {
        return this.message;
    }
    get typeError() {
        return true;
    }
};

在 RxTypeError 构造函数内部,会调用 messageForError 函数,生成异常消息:

代码语言:javascript
复制
const messageForError = (message, parameters) => {
    return 'RxError:' + '\n' +
        message + '\n' +
        parametersToString(parameters);
};

在 messageForError 函数内部,会进一步调用 parametersToString 函数进行参数对象

代码语言:javascript
复制
/**
 * transform an object of parameters to a presentable string
 * @param  {any} parameters
 * @return {string}
 */
const parametersToString = (parameters) => {
   	// { minPassLength, password }
    let ret = '';
    if (Object.keys(parameters).length === 0)
        return ret;
    ret += 'Given parameters: {\n';
    ret += Object.keys(parameters) // [minPassLength, password]
        .map(k => {
            let paramStr = '[object Object]';
            try {
                paramStr = JSON.stringify(
                    parameters[k],
                    (k, v) => v === undefined ? null : v,
                    2
                );
            } catch (e) {}
            return k + ':' + paramStr;
        })
        .join('\n');
    ret += '}';
    return ret;
};

JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON 字符串,如果指定了 replacer 是一个函数,则可以替换值,或者如果指定了 replacer 是一个数组,可选的仅包括指定的属性。

关于序列化,有下面五点注意事项:

  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
  • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
  • 不可枚举的属性会被忽略。
代码语言:javascript
复制
JSON.stringify({});                        // '{}'
JSON.stringify(true);                      // 'true'
JSON.stringify("foo");                     // '"foo"'
JSON.stringify([1, "false", false]);       // '[1,"false",false]'
JSON.stringify({ x: 5 });                  // '{"x":5}'

JSON.stringify({x: 5, y: 6});              
// "{"x":5,"y":6}"

JSON.stringify([new Number(1), new String("false"), new Boolean(false)]); 
// '[1,"false",false]'

分析完 RxError.newRxTypeError,我们再来看一下 newRxError 函数。

newRxError 函数

代码语言:javascript
复制
export const newRxError = (code, parameters) => 
  new RxError(code, overwritable.tunnelErrorMessage(code), parameters);

RxError 类继承于 Error 类,具体实现如下:

代码语言:javascript
复制
export class RxError extends Error {
    constructor(code, message, parameters = {}) {
        const mes = messageForError(message, parameters);
        super(mes);
        this.code = code;
        this.message = mes;
        this.parameters = parameters;
        this.rxdb = true; // tag them as internal
    }
    get name() {
        return 'RxError';
    }
    toString() {
        return this.message;
    }
    get typeError() {
        return false;
    }
};

另外在创建异常消息时,内部会调用 overwritable.tunnelErrorMessage() 方法生成 code 对应的异常消息:

代码语言:javascript
复制
 /**
     * overwritte to map error-codes to text-messages
     * @param  {string} message
     * @return {string}
     */
tunnelErrorMessage(message) {
  // TODO better text with link
    return `RxDB Error-Code ${message}.
     - To find out what this means, use the error-messages-plugin 
     https://pubkey.github.io/rxdb/custom-build.html#error-messages
     - Or search for this code https://github.com/pubkey/rxdb/search?  
     l=JavaScript&q=${message}%3A`;
}

不知道小伙伴有没有注意到 ‘EN1’ 和 ‘EN2’ 异常码,这些异常代码统一的定义在 error-message.js 文件的 CODES 对象中,该对象统一定义了 RxDB 中的所有异常信息:

代码语言:javascript
复制
const CODES = {
    // util.js
    UT1: 'given name is no string or empty',
    UT2: `collection- and database-names must match the regex`
    
  // plugins/encryption.js
    EN1: 'password is no string',
    EN2: 'validatePassword: min-length of password not complied',
}

此外在 error-message 插件内部会重写默认的 tunnelErrorMessage 方法,从而正常的显示异常消息:

代码语言:javascript
复制
export const overwritable = {
    tunnelErrorMessage(code) {
        if (!CODES[code]) {
            console.error('RxDB: Error-Code not known: ' + code);
            throw new Error('Error-Cdoe ' + code + ' not known, contact the maintainer');
        }
        return CODES[code];
    }
};

最后再总结一下异常的处理流程:

  • 调用 RxError 对象的 newRxTypeError() 方法,创建异常内置的异常对象。例如:RxError.newRxTypeError('EN1', { password })
  • 在 newRxTypeError 函数内部,会调用 overwritable.tunnelErrorMessage(code) 方法,根据异常代码,找出对应的异常信息(异常信息按照功能进行分类,定义在 error-message.js 文件内)。
  • 之后调用 RxTypeError 构造函数,创建 RxTypeError 对象。在 RxTypeError 构造函数内部,会对传入的参数对象进行序列化处理,然后与 code 对应的错误信息进行拼接,最终生成完整异常信息。

总结

  • 在 RxDB 内部主要定义了两个异常类:RxError 和 RxTypeError,并提供了 newRxTypeError 和 newRxError 两个函数,用于快速创建异常对象。
  • RxDB 异常处理机制,根据功能对异常代码进行分类,从而实现异常信息的统一管理。常见模块对应的异常代码映射关系如下:
    • UT —— util.js
    • P —— pouch-db.js
    • QU —— rx-query.js
    • MQ —— mquery.js
    • DB —— rx-database
    • COL —— rx-collection
    • EN —— plugins/encryption.js
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/09/05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基础知识
  • 异常对象分类
  • newRxTypeError 函数
  • newRxError 函数
  • 总结
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档