提出问题

下面的代码在有初始值的情况下,能够工作的很好,但是当localStorage中存在非法的数据时就会抛出异常,如果你的程序没有做好异常处理,就会崩溃。

const todosStr = localStorage.getItem('todos')
const todos = JSON.parse(todosStr)

分析问题

能够抛出异常的位置在JSON.parse,当JSON.parse解析的内容为以下情况时,就会抛出异常:

1 传参是无效的json字符串

JSON.parse("{name: 'John'}");
// Uncaught SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
JSON.parse('')
// Uncaught SyntaxError: Unexpected end of JSON input

2 解析的内容是undefined

JSON.parse(undefined)
// Uncaught SyntaxError: Unexpected end of JSON input

解决问题

知道了JSON.parse可能会抛出异常,我们在使用localStorage时做一下异常处理:

function getFromLocalStorage(key) {
  try {
    return JSON.parse(localStorage.getItem(key));
  } catch (error) {
    console.error(`Error parsing data from localStorage key "${key}": ${error}`);
    return null;
  }
}

我们在异常发生的时候,返回了nullgetItem在获取不到数据时也是返回null,这样用户就可以平滑的做空处理。

const todos = getFromLocalStorage('todos') || [];

总结问题

1 只做最关键的工作
我们没有在localStorage.getItem('todos')处做额外的异常处理和空判断,因为问题的源头发生在JSON.parse处。

2 保持接口的一致性
我们在异常处理时,与getItem保持了一致的返回值,这样在调用处就不用担心意料之外的情况发生。

3 只封装不可变的部分
我们没有将空判断放到函数里面,因为这是可变的部分,目标数据可能是字符串,也可能是数组,如果封装到内部就不够灵活了。相反,在外面做空判断就非常灵活。

注意

如果是在ts中,还需要对localStorage.getItem(key)做一下null的判断,因为ts判断JSON.parse只能接受字符串。

function getFromLocalStorage(key: string) {
  const data = localStorage.getItem(key)

  if (data === null) {
    return null;
  }

  try {
    return JSON.parse(data);
  } catch (error) {
    console.error(`Error parsing data from localStorage key "${key}": ${error}`);
    return null;
  }
}

热饭班长
3.7k 声望434 粉丝

先去做,做出一坨狗屎,再改进。