JavaScript非同步程式設計與回呼函式(Callbacks)

JavaScript默認是同步的,並且是單線程的。這意味著程式碼無法創建新的線程並且並行運行。了解一下非同步程式碼的含義以及它是什麼樣子。 程式語言中的非同步性 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', () => { //視窗已加載 //執行你想做的事情 }) 回呼函式無處不在,不僅僅在DOM事件中使用。 一個常見的例子是定時器: setTimeout(() => { //2秒後執行 }, 2000) XHR請求也接受回呼函式,這個例子中通過將一個函式賦值給一個屬性,在特定事件發生時調用該函式(在此例中,是請求狀態發生改變): const xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr....