Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

处理JSON方法异常引发的思考 #66

Open
Lotus1717 opened this issue Mar 28, 2019 · 0 comments
Open

处理JSON方法异常引发的思考 #66

Lotus1717 opened this issue Mar 28, 2019 · 0 comments

Comments

@Lotus1717
Copy link

Lotus1717 commented Mar 28, 2019

背景

mgm库的Storage组件对localStorage的存取方法没有对数据做异常处理导致报错:

set (key, value) {
    window.localStorage.setItem(prefix + key,JSON.stringify(value))
  },
  
get (key) {
    const v = window.localStorage.getItem(prefix + key)
    return v ? JSON.parse(v) : v
 }

报错场景:

  1. JSON.parse解析undefined值
  2. JSON.parse解析的值不符合 JSON规范

解决思路

  1. 防止localStorage存入undefined值
  2. 利用try catch控制程序流,捕捉代码异常

如何处理localStorage

localStorage的键值对总是以字符串的形式存储。对于不是string类型的值,会自动执行toString()方法。然而,对于对象或数组而言,这个转换会丢失它原本的类型信息,导致值在取出的时候不能变为原来的格式。举例:
【例1】localStorage.setItem('a', [1, 2, 3])
结果:localStorage的键值对依次是‘a'、'1,2,3'

【例2】localStorage.setItem('a', {a: 1})
结果:ocalStorage的键值对依次是‘a'、'[object, object]'

所以,为了避免在数据转换过程中类型丢失,当我们要存入对象,数组的时候,要以某种编码方式把值做处理,转化为字符串再存进localStorage。这里用到的是JSON数据交换格式。值在存入localStorage前用JSON.stringify方法转化为符合JSON格式的值,从localStorage取出后用JSON.parse方法解析为原来的值。

关于JSON

JSON具有以下形式:

  1. object
  2. array
  3. value: 可以是双引号括起来的字符串(string)、数值(number)、true、false、null、object或者array。这些结构可以嵌套。

MDN上关于循环引用的对象不可序列化的限制是错的,实际验证了并没有(一开始没有验证,差点信了,还是要多动手试试)。stringify方法内部已经把这个循环引用给过滤了。举例:
【例3】

var A = {a: B, c: 1}, B = {b: A}; 
JSON.stringify(A);

结果:”{“a”:{“b”:{“c”:1}},”c”:1}”

需要注意的是,对于symbol类型值和undefined,序列化的结果是undefined。但是undefined值在解析的时候会报错,所以在把数据存入localStorage的时候把undefined值过滤掉,避免报错。

关于‘undefined'的序列化处理
JSON.stringify用法: JSON.stringify(value[, replacer [, space]])

第二个参数是一个函数,可以在序列化过程中处理被序列化的值的属性。一开始我是想着用这个replacer函数j将’undefined’转换为undefined,这样子序列化的时候自然会把undefined忽略掉。

这也是一开始跟雅堂有争议的地方,‘undefined’这个字符串是不是有意义的,需不需要在序列化的时候过滤掉。我考虑的是值在运行时候的不确定性产生的’undefined‘并非喜闻乐见(想了想,好像自己也很少碰见程序莫名其妙跑出个’undefined‘值),索性把它干掉。雅堂考虑的是从字符串本身出发,它是有意义的。想了想,干预过多并非好事,就像用户的行为由他本身解释,字符串本身也应该自己解释自己才对。而且,程序的值如果是只是单纯的读写的话,更不要随意的手动更改。

try catch

不符合JSON规范的值解析会报异常,但传进JSON方法的值是不能在编写代码时确定的,因为JavaScript是一门动态类型语言,变量只有在运行过程中才能确定值的类型。因此,在程序运行过程中JSON.parse方法很可能传入一个非JSON规范的值。所以对于这种可能发生的程序异常,需要使用异常处理机制来防止代码报错,提升程序的容错能力。这里程序的异常处理用到了try catch异常处理机制。序列化和解析数据的代码放在try代码块中,如果有异常数据导致方法报错的话,在catch内部便可以捕捉到程序异常,并打印出警告。

关于console

console对象有很多方法属性可以辅助开发的,我经常用console.log方法打印日志,以致于信息不区分轻重全部log,这样容易忽略掉一些值得注意的程序异常。这里是数据异常引发方法运行出错,应该用console.warn方法输出警告信息,提醒开发者报错。

最终代码

set (key, value) {
    try {
      value && window.localStorage.setItem(prefix + key, JSON.stringify(value))
    } catch (e) {
      console.warn(e)
    }
  },
  get (key) {
    try {
      const v = window.localStorage.getItem(prefix + key)
      return v ? JSON.parse(v) : v
    } catch (e) {
      console.warn(e)
    }
  }
@Lotus1717 Lotus1717 changed the title 处理JSON序列化异常引发的思考 处理JSON方法异常引发的思考 Apr 9, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant