與數據庫交互看起來是一個很簡單的事情,但由於Node.js的異步性質使得這一切並不是那麼簡單。通過Node.js編寫異步代碼有很多選擇,每個都需要進行不同編碼。在本系列中,我們將提供一些示例來說明如何利用各種異步模式獲取、使用和關閉連接。在這篇文章中,我們將探討異步編程與傳統編程的區別。
try…catch…finally
JavaScript有一個try…catch…finally語句,try…catch部分很容易:運行某些代碼並捕獲異常,以便它們得到適當處理。但為什麼我們需要finally?finally提供了一種允許你運行代碼清理的方法,無論異常在try還是catch塊中。清理代碼通常包括關閉文件處理和數據庫鏈接。
下面是例子:

如果你在瀏覽器控制台(或者Node.js)中運行,你會在控制到看到類似內容:

請注意catch塊中引發的bar異常最終會作為未處理的異常,但在finally塊執行之前不會起作用。
如果我們在Node.js中運行的所有代碼都是異步,我們可以這樣做:
不幸的是,try…catch…finally對於異步代碼並不是非常有用—至少在異步函數可用之前,原因與Node.js中異步工作原理有關。
異步/事件處理
下面讓我們看看異步操作如何執行,例如執行HTTP請求和執行數據庫查詢。

所有JavaScript代碼在主線程運行,異步API從主線程調用並傳遞迴調函數。根據類型不同,異步工作可能完全作為事件或者可能利用線程池。當異步工作完成時,回調函數被添加到回調對象,以便儘快在主線程上調用。
對於這種架構,在異步處理期間發生的錯誤會在完全不同的調用堆棧中帶回到主線程。你不能捕捉在不同調用堆棧中引發的錯誤—為時太晚!
下面是調用異步API的非常簡單的演示:
setTimeout(function() {
console.log(‘hello’);
}, 2000);
console.log(‘world’);
如果你在瀏覽器控制台或Node.js中運行該腳本,則輸出是:
world
hello
在hello前兩秒看到world會讓異步編程新手感到驚訝。這裡的秘密是傳遞到setTimeout的回調函數,它會「回調」,或者當指定時間過去時在主線程執行。
回調函數可追溯到JavaScript的開始,JavaScript被設計為將生活帶到網絡的語言。JavaScript開發人員需要將代碼與事件關聯(例如加載頁面、點擊鼠標或者按鍵),隨着時間推移,下面這種DOM API被引入:
window.addEventListener(‘load’, function() {
// do some work
});
上面的addEventListener方法將傳入的異步函數作為第二個參數,並將其添加到windows元素load event相關的偵聽器列表中。當該事件發生時,所有監聽器被添加到回調對象,並將儘快被調用。
為了讓回調正常工作,JavaScript中的函數需要重要的功能:它們需要是第一類對象,並需要關閉。
函數作為第一類
函數作為第一類對象的概念聽起來很複雜。大多數編程語言提供了聲明變量和創建命名代碼單元的方法,通常被稱為函數或過程。這兩種結構之間通常有明確的區別,例如,你可以聲明變量並將其傳遞給函數,但你不能將函數傳遞給函數。
另一方面,JavaScript允許函數可用作更標準數據類型(例如Number、String和Boolean)。函數可以被聲明,從函數傳遞到函數,並可在未來某個時候被調用。函數作為第一類對象是傳遞函數到另一函數的前提條件。
想像一下,當頁面加載以及當用戶點擊窗口時你想要執行相同的代碼,你可以這樣做:
window.addEventListener(‘load’, function() {
// do some work
});
window.addEventListener(‘click’, function() {
// do the same work here
});
上面代碼的問題在於我們需要維持做相同工作的兩個函數。然後,如果知道函數是第一類對象,我們可聲明單一的命名函數,並根據需要傳遞引用。
function doWork() {
// do some work
}
window.addEventListener(‘load’, doWork);
window.addEventListener(‘click’, doWork);
你可以看到,函數作為第一類對象是簡單而強大的JavaScript功能。
函數提供閉合
閉合的概念可能有點難理解,但它對異步/事件編程來說至關重要。簡單來說,閉合是指在其封閉範圍定義的變量的函數。
很多語言允許開發人員在函數中嵌套函數,子函數可引用父函數範圍中聲明的變量。使用其他語言的開發人員可能永遠不會想到,如果在父函數完成執行後運行時調用子函數會發生什麼?這根本不可能,但JavaScript並非如此!
請記住,JavaScript中的函數是第一類對象,所以與分配給變量的任何其他值一樣,它們可通過傳遞來逃避其父函數的限制。當發生這種情況時,原始封閉範圍(詞彙範圍)內對變量的引用仍將存在。那麼,在以後調用子函數時應該怎麼辦?
閉合確保子函數能夠訪問這些變量,只要運行時可能需要調用子函數。這些變量不會像平常那樣作為垃圾回收。
下面是示例:

你可將此代碼複製並粘貼到具有.html擴展名的文件中,並在瀏覽器中打開。你會看到一個按鈕寫着「點擊我」,當窗口加載時,onLoad函數會將onClick函數註冊到按鈕的click事件。
請注意,onClick不會在onLoad內調用。相反,應用被傳遞到API,可在未來調用該函數。因為onClick是指onLoad函數中聲明的button變量,閉合可確保onClick在未來調用時可訪問button。
現在我們已經探討了JavaScript中異步編程相關的一些核心概念,下面讓我們將注意力轉移到Node.js中涉及的異步模式。
常見異步模式
目前,通過Node.js編寫異步代碼最常見(通用)模式是回調、異步模塊和promise。Node.js 7.6版本升級到8版本,其中引入了被稱為異步函數的異步處理新方法。
異步函數允許Javascript代碼異步編寫,且可異步執行。最重要的是,異步結構可按照你期望的方式運作。對於JavaScript來說,異步函數是重要變革,但promise以及異步處理仍然很重要。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/221344.html