1. 為什麼要處理異常?
如果我們不處理異常的話,直接會導致程式奔潰,使用者體驗比較差,因此我們要對異常進行處理,當出現異常的情況下,我們要給使用者一個友好的提示,並且記錄該異常,方便我們排查。
2. 在Node.js中常用的異常處理方式有哪些?
2.1 使用try catch方式來處理異常,如下程式碼:
try { throw new Error('error'); } catch(e) { console.log('異常被捕獲了,我現在還可以繼續執行了'); console.log(e); }
然後執行命令列時候,可以看到如下,也會列印後面的 console.log的資訊了;如下所示:
但是使用 try catch 無法處理非同步程式碼塊內出現的異常,比如如下程式碼:
try { setTimeout(() => { throw new Error('error'); }) } catch(e) { console.log('異常被捕獲了,我現在還可以繼續執行了'); console.log(e); }
在命令列中列印資訊如下:
可以看到,catch裡面的console.log(''); 程式碼並沒有被執行。說明catch裡面的程式碼異常並沒有被捕獲到。
2.2 使用event方式來處理異常
const events = require('events'); // 建立一個事件監聽物件 const emitter = new events.EventEmitter(); // 監聽error事件 emitter.addListener('error', (e) => { // 處理異常資訊 console.log(11122222); // 能列印 1112222 說明異常捕獲到了 console.log(e); }); // 觸發 error事件 emitter.emit('error', new Error('你程式碼出錯了'));
執行效果如下圖所示:
2.3 callback的方式
比如讀取一個檔案,或者建立一個目錄,測試程式碼如下:
const fs = require('fs'); fs.mkdir('/dir', (e) => { if (e) { console.log('異常資訊處理'); console.log(e); } else { console.log('建立目錄成功'); } });
然後執行結果如下圖所示:
2.4 Promise方式
new Promise((resolve, reject) => { throw new Error('error'); }).then(() => { // 。。。。 }).catch((e) => { console.log('能進來說明可以處理異常資訊了'); console.log(e); });
執行結果如下圖所示:
如上是處理同步程式碼,但是如果是非同步程式碼呢?繼續如下程式碼測試:
new Promise((resolve, reject) => { setTimeout(() => { throw new Error('error'); }, 100); }).then(() => { // 。。。。 }).catch((e) => { console.log('能進來說明可以處理異常資訊了'); console.log(e); });
然後執行結果如下所示:
可以看到,Promise也是一樣無法捕獲非同步程式碼中的異常資訊了。
2.5 Async/Await 方式
Async/Await 也是基於Promise的,Promise是無法捕獲非同步異常,因此Async/Await 也是沒有辦法捕獲的。如下測試程式碼:
先看同步程式碼可以捕獲到的,程式碼如下:
const testFunc = function() { return new Promise((resolve, reject) => { throw new Error('error'); }); }; async function testAsync() { try { await testFunc(); } catch (e) { console.log('能進來,說明異常能處理'); console.log(e); } } testAsync();
執行結果如下所示:
我們再看非同步程式碼,如下所示:
const testFunc = function() { setTimeout(() => { console.log(1111); return new Promise((resolve, reject) => { throw new Error('error'); }); }, 100); }; async function testAsync() { try { await testFunc(); } catch (e) { console.log('能進來,說明異常能處理'); console.log(e); } } testAsync();
如下圖所示:
2.6 process 方式(該方式既可以處理同步程式碼的異常,也可以處理非同步程式碼的異常)。
如下同步程式碼異常:
process.on('uncaughtException', (e) => { console.log('我能進來,說明可以處理異常'); console.log(e); }); function testFunc() { throw new Error('error'); } testFunc();
執行結果如下所示:
非同步程式碼如下所示:
process.on('uncaughtException', (e) => { console.log('我能進來,說明可以處理異常'); console.log(e); }); function testFunc() { setTimeout(() => { throw new Error('error'); }, 100); } testFunc();
如下圖所示:
2.7 domain 方式
domain也可以處理任何型別異常的資訊,包含同步和非同步。
如下同步程式碼所示:
const domain = require('domain'); const d = domain.create(); d.on('error', (e) => { console.log('我能進來,說明能處理異常'); console.log(e); }); d.run(() => { throw new Error('同步程式碼處理'); });
如下圖所示:
非同步程式碼如下所示:
const domain = require('domain'); const d = domain.create(); d.on('error', (e) => { console.log('我能進來,說明能處理異常'); console.log(e); }); d.run(() => { setTimeout(() => { throw new Error('非同步程式碼處理'); }, 100); });
如下圖所示: