提出問題
下面的代碼在有初始值的情況下,能夠工作的很好,但是當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;
}
}
我們在異常發生的時候,返回了null,getItem在獲取不到數據時也是返回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;
}
}