首頁 web前端 js教程 非同步 JavaScript - 從回呼到非同步等待的旅程

非同步 JavaScript - 從回呼到非同步等待的旅程

Nov 29, 2024 am 03:41 AM

作為一種單執行緒語言,JavaScript 一直依賴非同步程式設計來處理耗時的任務而不阻塞程式碼執行。多年來,JavaScript 中處理非同步性的方法已經發生了顯著的發展,變得更易於閱讀、更容易管理、更容易推理。讓我帶您了解非同步 JavaScript 的歷史,從回呼到 Promise,再到 async/await。

同步 JavaScript:誕生

在 JavaScript 的早期,在廣泛採用回呼之前,大多數 JavaScript 程式碼都是同步編寫的。同步程式碼意味著每個操作都以阻塞方式依序執行。當遇到長時間運行的操作時,整個腳本的執行將暫停,直到該操作完成。

想像一下,您在火車站售票櫃檯,只有一名售票員。您申請門票,售票員開始處理您的要求。在同步模型中,您必須在櫃檯等待,直到售票員處理完您的請求並將門票交給您。在此期間,無法為其他人提供服務,整個售票櫃檯都被封鎖了。

Asynchronous JavaScript - The Journey from Callbacks to Async Await

這是同步 JavaScript 程式碼的範例:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

登入後複製
登入後複製
登入後複製
登入後複製

在此程式碼中,console.log 語句將依序執行,長時間執行的動作(for 迴圈)將阻止腳本的執行,直到完成。 「操作後」訊息僅在循環結束後才會記錄。

同步程式碼的問題

雖然同步程式碼易於理解和推理,但它會帶來一些問題,特別是在處理耗時的操作時:

  1. 阻塞執行:長時間運行的操作會阻塞整個腳本的執行,使網頁或應用程式無回應,直到操作完成。
  2. 糟糕的使用者體驗:阻塞執行可能會導致糟糕的使用者體驗,因為使用者必須等待操作完成才能與應用程式互動。
  3. 資源利用效率低:同步程式碼無法有效利用系統資源,因為它在等待作業完成時無法執行其他任務。

為了克服同步程式碼的限制並提供更好的使用者體驗,引入了非同步程式設計技術。非同步程式允許在背景執行長時間運行的操作,而不會阻止其餘程式碼的執行,這就是回呼的引入方式。

回調:早期

回呼是處理非同步操作的主要方式。回調只是作為參數傳遞給另一個函數的函數,稍後在非同步操作完成後執行。

想像一下您想買一張火車票。您前往火車站的售票櫃檯索取特定目的地的車票。售票員接受您的請求並要求您稍候,他們會檢查火車上的空座情況。您向他們提供您的聯絡資訊並在等候區等候。一旦售票員處理了您的請求並且有空位,他們就會叫出您的名字,讓您知道您的票已準備好領取。在這個類比中,您的聯絡資訊就是回調 - 售票員在非同步任務(檢查座位可用性和出票)完成時通知您的一種方式。

Asynchronous JavaScript - The Journey from Callbacks to Async Await

以下是 JavaScript 中的回呼的類比:

  • 請求火車票就像呼叫一個以回呼作為參數的非同步函數。
  • 向售票員提供您的聯絡資訊就像將回呼函數傳遞給非同步函數。
  • 售票員檢查座位可用性並處理您的請求就像正在執行的非同步操作。
  • 票準備好後,售票員喊出你的名字,就像非同步操作的結果呼叫回呼函數一樣。
  • 您在等待區等待就像在處理非同步操作時繼續執行其餘的程式碼。

在回呼方法中,您提供一個函數(回呼),非同步操作完成後將呼叫該函數。非同步函數執行其任務,然後使用結果或錯誤呼叫回調,從而允許您的程式碼處理非同步操作的結果。

以下是在 Node.js 中使用回呼進行 API 呼叫的範例:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

登入後複製
登入後複製
登入後複製
登入後複製

在此範例中,我們有一個模擬 API 呼叫的 fetchData 函數。它接受一個 url 參數和一個回調函數作為參數。在函數內部,我們使用 setTimeout 來模擬呼叫回呼函數之前 1000 毫秒(1 秒)的延遲。

回呼函數遵循常見約定,接受錯誤為第一個參數 (err),接受資料作為第二個參數 (data)。在此範例中,我們透過將錯誤設為 null 並提供範例資料物件來模擬成功的 API 呼叫。

要使用 fetchData 函數,我們使用 URL 和回呼函數來呼叫它。在回調函數中,我們首先透過檢查 err 參數來檢查是否發生錯誤。如果有錯誤,我們使用 console.error 將其記錄到控制台並返回以停止進一步執行。

如果沒有發生錯誤,我們使用console.log將接收到的資料記錄到控制台。

當您執行此程式碼時,它將模擬非同步 API 呼叫。延遲1秒後,將呼叫回呼函數,並將結果記錄到控制台:

{ id: 1, name: 'John Doe' }

此範例示範如何使用回呼來處理非同步 API 呼叫。回呼函數會作為參數傳遞給非同步函數 (fetchData),並在非同步操作完成後呼叫它,無論是出現錯誤還是結果資料。

雖然回調完成了工作,但它們有幾個缺點:

Asynchronous JavaScript - The Journey from Callbacks to Async Await

  1. 回呼地獄/末日金字塔:嵌套多個非同步操作會導致程式碼深度嵌套和縮進,導致難以閱讀和維護。
  2. 錯誤處理:在每個巢狀層級處理錯誤非常麻煩,並且經常導致重複的程式碼。
  3. 缺乏可讀性:回調的非線性性質使程式碼更難以理解和推理。

承諾:向前邁出一步

為了解決回呼所帶來的挑戰,ES6 (ECMAScript 2015) 中引入了 Promise。 Promise 代表非同步操作的最終完成或失敗,並允許您將操作連結在一起。

將承諾想像成一張火車票。當您購買火車票時,該車票代表鐵路公司對您能夠登上火車並到達目的地的承諾。車票上包含有關火車的信息,例如出發時間、路線和座位號。拿到車票後,就可以等待火車到車站,準備上車後,就可以憑車票上車了。

在這個比喻中,火車票就是承諾。它代表非同步操作(火車旅程)的最終完成。您保留票(承諾對象),直到火車準備好(非同步操作完成)。一旦承諾得到解決(火車到車站),您就可以使用車票登上火車(獲取解決值)。

以下是 JavaScript 中的 Promise 的類比:

  • 購買火車票就像呼叫一個返回承諾的非同步函數。
  • 火車票本身就是promise對象,代表非同步操作的未來結果。
  • 等待火車到達就像等待承諾被解決或拒絕。
  • 拿著車票登上火車就像使用 .then() 來存取 Promise 的解析值。
  • 如果火車取消(發生錯誤),就像承諾被拒絕一樣,你可以使用 .catch() 來處理它。

Promise 提供了一種結構化的方式來處理非同步操作,讓您可以將多個操作連結在一起並以更易於管理的方式處理錯誤,就像火車票如何幫助您組織和管理火車旅程一樣。

Asynchronous JavaScript - The Journey from Callbacks to Async Await

這是使用 Promise 進行 API 呼叫的範例:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

登入後複製
登入後複製
登入後複製
登入後複製

在此程式碼中,fetchData 函數傳回一個承諾。 Promise 建構函式採用一個接受兩個參數的函式:resolve 和reject。這些函數用於控制 Promise 的狀態。

在 Promise 建構函數中,我們使用 setTimeout 模擬 API 調用,就像前面的範例一樣。然而,我們沒有呼叫回調函數,而是使用resolve和reject函數來處理非同步結果。

如果發生錯誤(在本例中,我們透過檢查錯誤變數來模擬錯誤),我們會呼叫帶有錯誤的拒絕函數,表示該 Promise 應該被拒絕。

如果沒有發生錯誤,我們將使用資料呼叫resolve函數,表示應使用接收到的資料來解析promise。

要使用 fetchData 函數,我們將 .then() 和 .catch() 方法連結到函數呼叫。 .then() 方法用於處理 Promise 的解析值,而 .catch() 方法用於處理可能發生的任何錯誤。

如果 Promise 成功解析,則會使用解析後的資料呼叫 .then() 方法,並使用 console.log 將其記錄到控制台。

如果發生錯誤且 Promise 被拒絕,則會使用 err 物件呼叫 .catch() 方法,然後我們使用 console.error 將其記錄到控制台。

與回呼相比,使用 Promise 提供了一種更結構化和可讀的方式來處理非同步操作。 Promise 可讓您使用 .then() 將多個非同步操作連結在一起,並使用 .catch() 以更集中的方式處理錯誤。

Promise 透過多種方式改善了回調:

  1. 連結:Promise 允許您使用 .then 將多個非同步操作連結在一起,使程式碼更具可讀性且更易於遵循。
  2. 錯誤處理:Promise 提供了 .catch 方法,以更集中和簡化的方式處理錯誤。
  3. 可讀性:Promise 讓非同步程式碼看起來更像同步程式碼,提高了可讀性。

但是,Promise 仍然有一些限制。連結多個 Promise 仍然可能導致深度嵌套的程式碼,並且語法並不像應有的那麼乾淨。

非同步/等待:現代方法

ES8 (ECMAScript 2017) 中引入的 Async/await 建構在 Promise 之上,並提供了一種看起來更同步的方式來編寫非同步程式碼。

使用 async/await,您可以編寫外觀和行為類似於同步程式碼的非同步程式碼。這就像有一個私人助理幫你售票櫃檯。你只需等待你的助手帶著票回來,一旦他們回來,你就可以繼續你的旅程了。

這是使用 async/await 進行 API 呼叫的範例:

console.log("Before operation"); 

// Simulating a long-running operation 
for (let i = 0; i < 1000000000; i++) { 
// Performing some computation 
} 

console.log("After operation");

登入後複製
登入後複製
登入後複製
登入後複製

在此程式碼中,我們有一個名為 fetchData 的非同步函數,它採用表示 API 端點的 url 參數。在函數內部,我們使用 try/catch 區塊來處理 API 請求期間可能發生的任何錯誤。

我們在 fetch 函數之前使用 wait 關鍵字來暫停執行,直到 fetch 傳回的 Promise 得到解析。這表示函數將等到 API 請求完成後再繼續下一行。

收到回應後,我們使用await response.json() 將回應正文解析為JSON。這也是一個非同步操作,所以我們使用await來等待解析完成。

如果API請求和JSON解析成功,則從fetchData函數傳回資料。

如果 API 請求或 JSON 解析過程中發生任何錯誤,都會被 catch 區塊捕獲。我們使用 console.error 將錯誤記錄到控制台,並使用 throw err 重新拋出錯誤,將其傳播給呼叫者。

為了使用 fetchData 函數,我們有一個名為 main 的非同步函數。在 main 中,我們指定要從中取得資料的 API 端點的 url。

我們使用await fetchData(url)來呼叫fetchData函數並等待它回傳資料。如果 API 請求成功,我們會將收到的資料記錄到控制台。

如果 API 請求程序中發生任何錯誤,則會被 main 函數中的 catch 區塊捕獲。我們使用 console.error 將錯誤記錄到控制台。

最後我們呼叫main函數開始執行程式。

當您執行此程式碼時,它將使用 fetch 函數向指定的 URL 發出非同步 API 請求。如果請求成功,接收到的資料將記錄到控制台。如果發生錯誤,也會被捕獲並記錄。

將 async/await 與 fetch 函數結合使用,提供了一種乾淨且可讀的方式來處理非同步 API 請求。它允許您編寫外觀和行為類似於同步程式碼的非同步程式碼,使其更易於理解和維護。

Async/await 提供了幾個好處:

  1. 簡潔的程式碼:Async/await 允許您編寫看起來和感覺像同步程式碼的非同步程式碼,使其更加簡潔和可讀。
  2. 錯誤處理:Async/await 使用 try/catch 區塊進行錯誤處理,與具有 Promise 的 .catch 相比,這是一種更熟悉、更直觀的錯誤處理方式。
  3. 可讀性:Async/await 讓非同步程式碼更容易理解和推理,特別是對於熟悉同步程式設計的開發人員。

結論

Asynchronous JavaScript - The Journey from Callbacks to Async Await

總之,非同步 JavaScript 的演變,從回呼到 Promise 再到 async/await,一直是朝著更具可讀性、可管理性和可維護性的非同步程式碼邁進的旅程。每一步都建立在前一步的基礎上,解決了限制並改善了開發人員體驗。

如今,async/await 已被廣泛使用,並已成為 JavaScript 中處理非同步操作的首選方式。它允許開發人員編寫乾淨、簡潔且易於理解的非同步程式碼,使其成為每個 JavaScript 開發人員工具箱中的寶貴工具。

以上是非同步 JavaScript - 從回呼到非同步等待的旅程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1671
14
CakePHP 教程
1428
52
Laravel 教程
1331
25
PHP教程
1276
29
C# 教程
1256
24
Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

JavaScript在行動中:現實世界中的示例和項目 JavaScript在行動中:現實世界中的示例和項目 Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

了解JavaScript引擎:實施詳細信息 了解JavaScript引擎:實施詳細信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:社區,圖書館和資源 Python vs. JavaScript:社區,圖書館和資源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Python vs. JavaScript:開發環境和工具 Python vs. JavaScript:開發環境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

C/C在JavaScript口譯員和編譯器中的作用 C/C在JavaScript口譯員和編譯器中的作用 Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

See all articles