掌握 JavaScript 非同步模式:從回呼到非同步/等待
當我第一次遇到非同步 JavaScript 時,我在回調方面遇到了困難,並且不知道 Promises 在幕後是如何運作的。隨著時間的推移,對 Promise 和 async/await 的了解改變了我的編碼方法,使其更易於管理。在本部落格中,我們將逐步探索這些非同步模式,揭示它們如何簡化您的開發流程並使您的程式碼更乾淨、更有效率。讓我們一起深入探討並揭開這些概念!
為什麼需要學習異步 JavaScript?
學習非同步 JavaScript 對於現代 Web 開發至關重要。它允許您有效地處理 API 請求等任務,使您的應用程式保持快速回應。掌握非同步技術(例如 Promises 和 async/await)不僅對於建立可擴展的應用程式至關重要,而且對於在 JavaScript 工作面試中取得成功也至關重要,而理解這些概念通常是重點。透過掌握非同步 JavaScript,您將提高編碼技能並更好地為現實世界的挑戰做好準備。
什麼是異步模式?
JavaScript 中的非同步模式是用於處理需要時間的任務的技術,例如從伺服器獲取數據,而不凍結應用程式。最初,開發人員使用回調來管理這些任務,但這種方法通常會導致程式碼複雜且難以閱讀,稱為「回調地獄」。為了簡化這一點,引入了 Promise,透過連結操作和更優雅地處理錯誤,提供了一種更乾淨的方式來處理非同步操作。 async/await 繼續發展,它允許您編寫看起來和行為更像同步程式碼的非同步程式碼,從而更易於閱讀和維護。這些模式對於建立高效、反應迅速的應用程式至關重要,也是現代 JavaScript 開發的基礎。我們將在本部落格中更詳細地探討這些概念。
什麼是回調?
回呼 是作為參數傳遞給其他函數的函數,目的是讓接收函數在某個時刻執行回呼。這對於您希望確保某些程式碼在特定任務完成後運行的場景非常有用,例如從伺服器取得資料或完成計算後。
回呼如何運作:
- 您定義一個函數(回呼)。
- 您將此函數作為參數傳遞給另一個函數。
- 接收函數在適當的時間執行回呼。
範例 1
function fetchData(callback) { // Simulate fetching data with a delay setTimeout(() => { const data = "Data fetched"; callback(data); // Call the callback function with the fetched data }, 1000); } function processData(data) { console.log("Processing:", data); } fetchData(processData); // fetchData will call processData with the data
範例 2
// Function that adds two numbers and uses a callback to return the result function addNumbers(a, b, callback) { const result = a + b; callback(result); // Call the callback function with the result } // Callback function to handle the result function displayResult(result) { console.log("The result is:", result); } // Call addNumbers with the displayResult callback addNumbers(5, 3, displayResult);
注意:我認為回調對於處理非同步操作是有效的,但要小心:隨著程式碼複雜性的增加,尤其是嵌套回調,您可能會遇到稱為回調地獄的問題。當回呼彼此深度嵌套時,就會出現此問題,從而導致可讀性問題並使程式碼難以維護。
回調地獄
回調地獄(也稱為末日金字塔)指的是有多個嵌套回呼的情況。當您需要按順序執行多個非同步操作,並且每個操作都依賴前一個操作時,就會發生這種情況。
例如。這會創造一個難以閱讀和維護的「金字塔」結構。
fetchData(function(data1) { processData1(data1, function(result1) { processData2(result1, function(result2) { processData3(result2, function(result3) { console.log("Final result:", result3); }); }); }); });
回調地獄問題:
- 可讀性:程式碼變得難以閱讀和理解。
- 可維護性:進行更改或除錯變得具有挑戰性。
- 錯誤處理:管理錯誤可能會變得複雜。
使用回調處理錯誤
使用回呼時,通常使用稱為錯誤優先回呼的模式。在此模式中,回調函數將錯誤作為其第一個參數。如果沒有錯誤,第一個參數通常為 null 或未定義,實際結果會作為第二個參數提供。
function fetchData(callback) { setTimeout(() => { const error = null; // Or `new Error("Some error occurred")` if there's an error const data = "Data fetched"; callback(error, data); // Pass error and data to the callback }, 1000); } function processData(error, data) { if (error) { console.error("Error:", error); return; } console.log("Processing:", data); } fetchData(processData); // `processData` will handle both error and data
注意:在回調之後,引入了 Promise 來處理 JavaScript 中的非同步過程。我們現在將更深入地研究 Promise 並探索它們在幕後是如何運作的。
Promise 簡介
Promises 是表示非同步操作最終完成(或失敗)及其結果值的物件。與回調相比,它們提供了一種更簡潔的方式來處理非同步程式碼。
承諾的目的:
- Avoid Callback Hell: Promises help manage multiple asynchronous operations without deep nesting.
- Improve Readability: Promises provide a more readable way to handle sequences of asynchronous tasks.
Promise States
A Promise can be in one of three states:
- Pending: The initial state, before the promise has been resolved or rejected.
- Fulfilled: The state when the operation completes successfully, and resolve has been called.
- Rejected: The state when the operation fails, and reject has been called.
Note: If you want to explore more, you should check out Understand How Promises Work Under the Hood where I discuss how promises work under the hood.
example 1
// Creating a new promise const myPromise = new Promise((resolve, reject) => { const success = true; // Simulate success or failure if (success) { resolve("Operation successful!"); // If successful, call resolve } else { reject("Operation failed!"); // If failed, call reject } }); // Using the promise myPromise .then((message) => { console.log(message); // Handle the successful case }) .catch((error) => { console.error(error); // Handle the error case });
example 2
const examplePromise = new Promise((resolve, reject) => { setTimeout(() => { const success = Math.random() > 0.5; // Randomly succeed or fail if (success) { resolve("Success!"); } else { reject("Failure."); } }, 1000); }); console.log("Promise state: Pending..."); // To check the state, you would use `.then()` or `.catch()` examplePromise .then((message) => { console.log("Promise state: Fulfilled"); console.log(message); }) .catch((error) => { console.log("Promise state: Rejected"); console.error(error); });
Chaining Promises
Chaining allows you to perform multiple asynchronous operations in sequence, with each step depending on the result of the previous one.
Chaining promises is a powerful feature of JavaScript that allows you to perform a sequence of asynchronous operations where each step depends on the result of the previous one. This approach is much cleaner and more readable compared to deeply nested callbacks.
How Promise Chaining Works
Promise chaining involves connecting multiple promises in a sequence. Each promise in the chain executes only after the previous promise is resolved, and the result of each promise can be passed to the next step in the chain.
function step1() { return new Promise((resolve) => { setTimeout(() => resolve("Step 1 completed"), 1000); }); } function step2(message) { return new Promise((resolve) => { setTimeout(() => resolve(message + " -> Step 2 completed"), 1000); }); } function step3(message) { return new Promise((resolve) => { setTimeout(() => resolve(message + " -> Step 3 completed"), 1000); }); } // Chaining the promises step1() .then(result => step2(result)) .then(result => step3(result)) .then(finalResult => console.log(finalResult)) .catch(error => console.error("Error:", error));
Disadvantages of Chaining:
While chaining promises improves readability compared to nested callbacks, it can still become unwieldy if the chain becomes too long or complex. This can lead to readability issues similar to those seen with callback hell.
Note: To address these challenges, async and await were introduced to provide an even more readable and straightforward way to handle asynchronous operations in JavaScript.
Introduction to Async/Await
async and await are keywords introduced in JavaScript to make handling asynchronous code more readable and easier to work with.
- async: Marks a function as asynchronous. An async function always returns a promise, and it allows the use of await within it.
- await: Pauses the execution of the async function until the promise resolves, making it easier to work with asynchronous results in a synchronous-like fashion.
async function fetchData() { return new Promise((resolve) => { setTimeout(() => { resolve("Data fetched"); }, 1000); }); } async function getData() { const data = await fetchData(); // Wait for fetchData to resolve console.log(data); // Logs "Data fetched" } getData();
How Async/Await Works
1. Async Functions Always Return a Promise:
No matter what you return from an async function, it will always be wrapped in a promise. For example:
async function example() { return "Hello"; } example().then(console.log); // Logs "Hello"
Even though example() returns a string, it is automatically wrapped in a promise.
2. Await Pauses Execution:
The await keyword pauses the execution of an async function until the promise it is waiting for resolves.
async function example() { console.log("Start"); const result = await new Promise((resolve) => { setTimeout(() => { resolve("Done"); }, 1000); }); console.log(result); // Logs "Done" after 1 second } example();
In this example:
- "Start" is logged immediately.
- The await pauses execution until the promise resolves after 1 second.
- "Done" is logged after the promise resolves.
Error Handling with Async/Await
Handling errors with async/await is done using try/catch blocks, which makes error handling more intuitive compared to promise chains.
async function fetchData() { throw new Error("Something went wrong!"); } async function getData() { try { const data = await fetchData(); console.log(data); } catch (error) { console.error("Error:", error.message); // Logs "Error: Something went wrong!" } } getData();
With Promises, you handle errors using .catch():
fetchData() .then(data => console.log(data)) .catch(error => console.error("Error:", error.message));
Using async/await with try/catch often results in cleaner and more readable code.
Combining Async/Await with Promises
You can use async/await with existing promise-based functions seamlessly.
example
function fetchData() { return new Promise((resolve) => { setTimeout(() => { resolve("Data fetched"); }, 1000); }); } async function getData() { const data = await fetchData(); // Wait for the promise to resolve console.log(data); // Logs "Data fetched" } getData();
Best Practices:
- 使用 async/await 來提高可讀性:在處理多個非同步操作時,async/await 可以讓程式碼更線性,更容易理解。
- 與 Promise 結合:繼續使用 async/await 和基於 Promise 的函數來更自然地處理複雜的非同步流程。
- 錯誤處理: 始終在非同步函數中使用 try/catch 區塊來處理潛在的錯誤。
結論
與傳統的 Promise 鍊和回調相比,async 和 wait 提供了一種更清晰、更易讀的方式來處理非同步操作。透過允許您編寫外觀和行為類似於同步程式碼的非同步程式碼,它們可以簡化複雜的邏輯並使用 try/catch 區塊改進錯誤處理。將 async/await 與 Promise 一起使用會產生更易於維護和理解的程式碼。
以上是掌握 JavaScript 非同步模式:從回呼到非同步/等待的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

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

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

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

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

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

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

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。
