日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
從不用try-catch實(shí)現(xiàn)的async/await語(yǔ)法來(lái)說(shuō)說(shuō)錯(cuò)誤處理

[[208471]]

成都創(chuàng)新互聯(lián)主要從事成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、成都外貿(mào)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)介休,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專(zhuān)業(yè),歡迎來(lái)電咨詢(xún)建站服務(wù):13518219792

前不久看到 Dima Grossman 寫(xiě)的 How to write async await without try-catch blocks in Javascript??吹綐?biāo)題的時(shí)候,我感到非常好奇。我知道雖然在異步程序中可以不使用 try-catch 配合 async/await 來(lái)處理錯(cuò)誤,但是處理方式并不能與 async/await 配合得很好,所以很想知道到底有什么辦法會(huì)比 try-catch 更好用。

Dima 去除 try-catch 的方法

當(dāng)然套路依舊,Dima 講到了回調(diào)地獄,Promise 鏈并最終引出了 async/await。而在處理錯(cuò)誤的時(shí)候,他并不喜歡 try-catch 的方式,所以寫(xiě)了一個(gè) to(promise) 來(lái)對(duì) Promise 進(jìn)行封裝,輔以解構(gòu)語(yǔ)法,實(shí)現(xiàn)了同步寫(xiě)法但類(lèi)似 Node 錯(cuò)誤標(biāo)準(zhǔn)的代碼。摘抄代碼如下

 
 
 
  1. // to.js 
  2. export default function to(promise) { 
  3.     return promise 
  4.         .then(data => { 
  5.             return [null, data]; 
  6.         }) 
  7.         .catch(err => [err]); 
  8. }  

應(yīng)用示例:

 
 
 
  1. import to from "./to.js"; 
  2.  
  3. async function asyncTask(cb) { 
  4.     let err, user, savedTask; 
  5.  
  6.     [err, user] = await to(UserModel.findById(1)); 
  7.     if (!user) return cb("No user found"); 
  8.  
  9.     [err, savedTask] = await to(TaskModel({ userId: user.id, name: "Demo Task" })); 
  10.     if (err) return cb("Error occurred while saving task"); 
  11.  
  12.     if (user.notificationsEnabled) { 
  13.         const [err] = await to(NotificationService.sendNotification(user.id, "Task Created")); 
  14.         if (err) return cb("Error while sending notification"); 
  15.     } 
  16.  
  17.     cb(null, savedTask); 
  18. }  

Dima 的辦法讓人產(chǎn)生的了熟悉的感覺(jué),Node 的回調(diào)中不是經(jīng)常都這樣寫(xiě)嗎?

 
 
 
  1. (err, data) => { 
  2.     if (err) { 
  3.         // deal with error 
  4.     } else { 
  5.         // deal with data 
  6.     } 
  7. }  

所以這個(gè)方法真的很有意思。不過(guò)回過(guò)頭來(lái)想一想,這段代碼中每當(dāng)遇到錯(cuò)誤,都是將錯(cuò)誤消息通過(guò) cb() 調(diào)用推出去,同時(shí)中斷后續(xù)過(guò)程。像這種中斷式的錯(cuò)誤處理,其實(shí)正適合采用 try-catch。

使用 try-catch 改寫(xiě)上面的代碼

要用 try-catch 改寫(xiě)上面的代碼,首先要去掉 to() 封裝。這樣,一旦發(fā)生錯(cuò)誤,需要使用 Promise.prototype.catch() 進(jìn)行捕捉,或者使用 try-catch 對(duì) await promise 語(yǔ)句進(jìn)行捕捉。捕捉到的,當(dāng)然是每個(gè)業(yè)務(wù)代碼里 reject 出來(lái)的 err。

然而注意,上面的代碼中并沒(méi)有直接使用 err,而是使用了自定義的錯(cuò)誤消息。所以需要對(duì) reject 出來(lái)的 err 進(jìn)一步處理成指定的錯(cuò)誤消息。當(dāng)然這難不到誰(shuí),比如

 
 
 
  1. someAsync().catch(err => Project.reject("specified message")); 

然后再最外層加上 try-catch 就好。所以改寫(xiě)之后的代碼是:

 
 
 
  1. async function asyncTask(cb) { 
  2.     try { 
  3.         const user = await UserModel.findById(1) 
  4.             .catch(err => Promise.reject("No user found")); 
  5.  
  6.         const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }) 
  7.             .catch(err => Promise.reject("Error occurred while saving task")); 
  8.  
  9.         if (user.notificationsEnabled) { 
  10.             await NotificationService.sendNotification(user.id, "Task Created") 
  11.                 .catch(err => Promise.reject("Error while sending notification")); 
  12.         } 
  13.  
  14.         cb(null, savedTask); 
  15.     } catch (err) { 
  16.         cb(err); 
  17.     } 
  18. }  

上面這段代碼,從代碼量上來(lái)說(shuō),并沒(méi)有比 Dima 的代碼減少了多少工作量,只是去掉了大量 if (err) {} 結(jié)構(gòu)。不習(xí)慣使用 try-catch 的程序員找找不到中斷點(diǎn),但習(xí)慣了 try-catch 的程序員都知道,業(yè)務(wù)過(guò)程中一旦發(fā)生錯(cuò)誤(異步代碼里指 reject),代碼就會(huì)跳到 catch 塊去處理 reject 出來(lái)的值。

但是,一般業(yè)務(wù)代碼 reject 出來(lái)的信息通常都是有用的。假如上面的每個(gè)業(yè)務(wù) reject 出來(lái)的 err 本身就是錯(cuò)誤消息,那么,用 Dima 的模式,仍然需要寫(xiě)

 
 
 
  1. if (err) return cb(err); 

而用 try-catch 的模式,就簡(jiǎn)單多了

 
 
 
  1. async function asyncTask(cb) { 
  2.     try { 
  3.         const user = await UserModel.findById(1); 
  4.         const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }); 
  5.  
  6.         if (user.notificationsEnabled) { 
  7.             await NotificationService.sendNotification(user.id, "Task Created"); 
  8.         } 
  9.  
  10.         cb(null, savedTask); 
  11.     } catch (err) { 
  12.         cb(err); 
  13.     } 
  14. }  

為什么?因?yàn)樵?Dima 的模式中,if (err) 實(shí)際上處理了兩個(gè)業(yè)務(wù):一是捕捉會(huì)引起中斷的 err ,并將其轉(zhuǎn)換為錯(cuò)誤消息,二是通過(guò) return 中斷業(yè)務(wù)過(guò)程。所以當(dāng) err 轉(zhuǎn)換為錯(cuò)誤消息這一過(guò)程不再需要的時(shí)候,這種捕捉中斷再重新引起中斷的處理主顯得多余了。

繼續(xù)改進(jìn)

用函數(shù)表達(dá)式改善 try-catch 邏輯

當(dāng)然還有改進(jìn)的空間,比如 try {} 塊中的代碼比較長(zhǎng),會(huì)造成閱讀不太方便,try-catch 的邏輯有被“切斷”的感覺(jué)。這種情況下可以使用函數(shù)表達(dá)式來(lái)改善

 
 
 
  1. async function asyncTask(cb) { 
  2.     async function process() { 
  3.         const user = await UserModel.findById(1); 
  4.         const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }); 
  5.  
  6.         if (user.notificationsEnabled) { 
  7.             await NotificationService.sendNotification(user.id, "Task Created"); 
  8.         } 
  9.         return savedTask; 
  10.     } 
  11.  
  12.     try { 
  13.         cb(null, await process()); 
  14.     } catch (err) { 
  15.         cb(err); 
  16.     } 
  17. }  

如果對(duì)錯(cuò)誤的處理代碼比較長(zhǎng),也可以寫(xiě)成單獨(dú)的函數(shù)表達(dá)式。

如果過(guò)程中每一步的錯(cuò)誤處理邏輯不同怎么辦

如果發(fā)生錯(cuò)誤,不再轉(zhuǎn)換為錯(cuò)誤消息,而是特定的錯(cuò)誤處理邏輯,怎么辦?

思考一下,我們用字符串來(lái)表示錯(cuò)誤消息,以后可以通過(guò) console.log() 來(lái)處理處理。而邏輯,最適合的表示當(dāng)然是函數(shù)表達(dá)式,最終可以通過(guò)調(diào)用來(lái)進(jìn)行統(tǒng)一處理

 
 
 
  1. async function asyncTask(cb) { 
  2.     async function process() { 
  3.         const user = await UserModel.findById(1) 
  4.             .catch(err => Promise.reject(() => { 
  5.                 // deal with error on looking for the user 
  6.                 return "No user found"; 
  7.             })); 
  8.  
  9.         const savedTask = await TaskModel({ userId: user.id, name: "Demo Task" }) 
  10.             .catch(err => Promise.reject(() => { 
  11.                 // making model error 
  12.                 // deal with it 
  13.                 return err === 1 
  14.                     ? "Error occurred while saving task" 
  15.                     : "Error occurred while making model"; 
  16.             })); 
  17.  
  18.         if (user.notificationsEnabled) { 
  19.             await NotificationService.sendNotification(user.id, "Task Created") 
  20.                 .catch(err => Promise.reject(() => { 
  21.                     // just print a message 
  22.                     logger.log(err); 
  23.                     return "Error while sending notification"; 
  24.                 })); 
  25.         } 
  26.  
  27.         return savedTask; 
  28.     } 
  29.  
  30.     try { 
  31.         cb(null, await process()); 
  32.     } catch (func) { 
  33.         cb(func()); 
  34.     } 
  35. }  

甚至還可以處理更復(fù)雜的情況

現(xiàn)在應(yīng)該都知道 .catch(err => Promise.reject(xx)),這里的 xx 就是 try-catch 的 catch 塊捕捉到的對(duì)象,所以如果不同的業(yè)務(wù) reject 出來(lái)不同的對(duì)象,比如有些是函數(shù)(表示錯(cuò)誤處理邏輯),有些是字符串(表示錯(cuò)誤消息),有些是數(shù)字(表示錯(cuò)誤代碼)——其實(shí)只需要改 catch 塊就行

 
 
 
  1. try { 
  2.        // ...    
  3.    } catch(something) { 
  4.        switch (typeof something) { 
  5.            case "string": 
  6.                // show message something 
  7.                break; 
  8.            case "function": 
  9.                something(); 
  10.                break; 
  11.            case "number": 
  12.                // look up something as code 
  13.                // and show correlative message 
  14.                break; 
  15.            default: 
  16.                // deal with unknown error 
  17.        } 
  18.    }  

小結(jié)

我沒(méi)有批判 Dima 的錯(cuò)誤處理方式,這個(gè)錯(cuò)誤處理方式很好,很符合 Node 錯(cuò)誤處理的風(fēng)格,也一定會(huì)受到很多人的喜愛(ài)。由于 Dima 的錯(cuò)誤處理方式給帶靈感,同時(shí)也讓我再次審視了一直比較喜歡的 try-catch 方式。

用什么方式取決于適用場(chǎng)景、團(tuán)隊(duì)約定和個(gè)人喜好等多種因素,在不同的情況下需要采用不同的處理方式,并不是說(shuō)哪一種就一定好于另一種——合適的才是***的! 


文章名稱(chēng):從不用try-catch實(shí)現(xiàn)的async/await語(yǔ)法來(lái)說(shuō)說(shuō)錯(cuò)誤處理
網(wǎng)頁(yè)URL:http://www.dlmjj.cn/article/dhhjjog.html