nodejs.cn-Node.js-入門教程:JavaScript 非同步程式設計與回撥
ylbtech-nodejs.cn-Node.js-入門教程:JavaScript 非同步程式設計與回撥 |
1.返回頂部 |
JavaScript 非同步程式設計與回撥
目錄
程式語言中的非同步性
計算機在設計上是非同步的。
非同步意味著事情可以獨立於主程式流而發生。
在當前的使用者計算機中,每個程式都運行於特定的時間段,然後停止執行,以讓另一個程式繼續執行。 這件事執行得如此之快,以至於無法察覺。 我們以為計算機可以同時執行許多程式,但這是一種錯覺(在多處理器計算機上除外
程式在內部會使用中斷,一種被髮送到處理器以獲取系統關注的訊號。
這裡不會深入探討這個問題,只要記住,程式是非同步的且會暫停執行直到需要關注,這使得計算機可以同時執行其他操作。 當程式正在等待來自網路的響應時,則它無法在請求完成之前停止處理器。
通常,程式語言是同步的,有些會在語言或庫中提供管理非同步性的方法。 預設情況下,C、Java、C#、PHP、Go、Ruby、Swift 和 Python 都是同步的。 其中一些語言通過使用執行緒(衍生新的程序)來處理非同步操作。
JavaScript
JavaScript 預設情況下是同步的,並且是單執行緒的。 這意味著程式碼無法建立新的執行緒並且不能並行執行
程式碼行是依次執行的,例如:
const a = 1
const b = 2
const c = a * b
console.log(c)
doSomething()
但是 JavaScript 誕生於瀏覽器內部,一開始的主要工作是響應使用者的操作,例如onClick
、onMouseOver
、onChange
、onSubmit
等。 使用同步的程式設計模型該如何做到這一點?
答案就在於它的環境。 瀏覽器通過提供一組可以處理這種功能的 API 來提供了一種實現方式。
更近點,Node.js 引入了非阻塞的 I/O 環境,以將該概念擴充套件到檔案訪問、網路呼叫等。
回撥
你不知道使用者何時單擊按鈕。 因此,為點選事件定義了一個事件處理程式。 該事件處理程式會接受一個函式,該函式會在該事件被觸發時被呼叫:
document.getElementById('button').addEventListener('click', () => {
//被點選
})
這就是所謂的回撥。
回撥是一個簡單的函式,會作為值被傳給另一個函式,並且僅在事件發生時才被執行。 之所以這樣做,是因為 JavaScript 具有頂級的函式,這些函式可以被分配給變數並傳給其他函式(稱為高階函式)。
通常會將所有的客戶端程式碼封裝在window
物件的load
事件監聽器中,其僅在頁面準備就緒時才會執行回撥函式:
window.addEventListener('load', () => {
//window 已被載入。
//做需要做的。
})
回撥無處不在,不僅在 DOM 事件中。
一個常見的示例是使用定時器:
setTimeout(() => {
// 2 秒之後執行。
}, 2000)
XHR 請求也接受回撥,在此示例中,會將一個函式分配給一個屬性,該屬性會在發生特定事件(在該示例中,是請求狀態的改變)時被呼叫:
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
xhr.status === 200 ? console.log(xhr.responseText) : console.error('出錯')
}
}
xhr.open('GET', 'http://nodejs.cn')
xhr.send()
處理回撥中的錯誤
如何處理回撥的錯誤? 一種非常常見的策略是使用 Node.js 所採用的方式:任何回撥函式中的第一個引數為錯誤物件(即錯誤優先的回撥)。
如果沒有錯誤,則該物件為null
。 如果有錯誤,則它會包含對該錯誤的描述以及其他資訊。
fs.readFile('/檔案.json', (err, data) => {
if (err !== null) {
//處理錯誤
console.log(err)
return
}
//沒有錯誤,則處理資料。
console.log(data)
})
回撥的問題
回調適用於簡單的場景!
但是,每個回撥都可以新增巢狀的層級,並且當有很多回調時,程式碼就會很快變得非常複雜:
window.addEventListener('load', () => {
document.getElementById('button').addEventListener('click', () => {
setTimeout(() => {
items.forEach(item => {
//你的程式碼在這裡。
})
}, 2000)
})
})
這只是一個簡單的 4 個層級的程式碼,但還有更多層級的巢狀,這很不好。
該如何解決?
回撥的替代方法
從 ES6 開始,JavaScript 引入了一些特性,可以幫助處理非同步程式碼而不涉及使用回撥:Promise(ES6)和 Async/Await(ES2017)。
2、2.返回頂部 |
3.返回頂部 |
4.返回頂部 |
5.返回頂部 |
6.返回頂部 |
作者:ylbtech 出處:http://ylbtech.cnblogs.com/ 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。 |