搜尋
首頁web前端js教程掌握 JavaScript 非同步模式:從回呼到非同步/等待

Mastering JavaScript Async Patterns: From Callbacks to Async/Await

當我第一次遇到非同步 JavaScript 時,我在回調方面遇到了困難,並且不知道 Promises 在幕後是如何運作的。隨著時間的推移,對 Promise 和 async/await 的了解改變了我的編碼方法,使其更易於管理。在本部落格中,我們將逐步探索這些非同步模式,揭示它們如何簡化您的開發流程並使您的程式碼更乾淨、更有效率。讓我們一起深入探討並揭開這些概念!

為什麼需要學習異步 JavaScript?

學習非同步 JavaScript 對於現代 Web 開發至關重要。它允許您有效地處理 API 請求等任務,使您的應用程式保持快速回應。掌握非同步技術(例如 Promises 和 async/await)不僅對於建立可擴展的應用程式至關重要,而且對於在 JavaScript 工作面試中取得成功也至關重要,而理解這些概念通常是重點。透過掌握非同步 JavaScript,您將提高編碼技能並更好地為現實世界的挑戰做好準備。

什麼是異步模式?

JavaScript 中的非同步模式是用於處理需要時間的任務的技術,例如從伺服器獲取數據,而不凍結應用程式。最初,開發人員使用回調來管理這些任務,但這種方法通常會導致程式碼複雜且難以閱讀,稱為「回調地獄」。為了簡化這一點,引入了 Promise,透過連結操作和更優雅地處理錯誤,提供了一種更乾淨的方式來處理非同步操作。 async/await 繼續發展,它允許您編寫看起來和行為更像同步程式碼的非同步程式碼,從而更易於閱讀和維護。這些模式對於建立高效、反應迅速的應用程式至關重要,也是現代 JavaScript 開發的基礎。我們將在本部落格中更詳細地探討這些概念。

什麼是回調?

回呼 是作為參數傳遞給其他函數的函數,目的是讓接收函數在某個時刻執行回呼。這對於您希望確保某些程式碼在特定任務完成後運行的場景非常有用,例如從伺服器取得資料或完成計算後。

回呼如何運作:

  1. 您定義一個函數(回呼)。
  2. 您將此函數作為參數傳遞給另一個函數。
  3. 接收函數在適當的時間執行回呼。

範例 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);
      });
    });
  });
});

回調地獄問題:

  1. 可讀性:程式碼變得難以閱讀和理解。
  2. 可維護性:進行更改或除錯變得具有挑戰性。
  3. 錯誤處理:管理錯誤可能會變得複雜。

使用回調處理錯誤

使用回呼時,通常使用稱為錯誤優先回呼的模式。在此模式中,回調函數將錯誤作為其第一個參數。如果沒有錯誤,第一個參數通常為 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 是表示非同步操作最終完成(或失敗)及其結果值的物件。與回調相比,它們提供了一種更簡潔的方式來處理非同步程式碼。

承諾的目的:

  1. Avoid Callback Hell: Promises help manage multiple asynchronous operations without deep nesting.
  2. 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:

  1. Pending: The initial state, before the promise has been resolved or rejected.
  2. Fulfilled: The state when the operation completes successfully, and resolve has been called.
  3. 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:

  1. 使用 async/await 來提高可讀性:在處理多個非同步操作時,async/await 可以讓程式碼更線性,更容易理解。
  2. 與 Promise 結合:繼續使用 async/await 和基於 Promise 的函數來更自然地處理複雜的非同步流程。
  3. 錯誤處理: 始終在非同步函數中使用 try/catch 區塊來處理潛在的錯誤。

結論

與傳統的 Promise 鍊和回調相比,async 和 wait 提供了一種更清晰、更易讀的方式來處理非同步操作。透過允許您編寫外觀和行為類似於同步程式碼的非同步程式碼,它們可以簡化複雜的邏輯並使用 try/catch 區塊改進錯誤處理。將 async/await 與 Promise 一起使用會產生更易於維護和理解的程式碼。

以上是掌握 JavaScript 非同步模式:從回呼到非同步/等待的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

如何使用Next.js(前端集成)構建多租戶SaaS應用程序如何使用Next.js(前端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript:探索網絡語言的多功能性JavaScript:探索網絡語言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的演變:當前的趨勢和未來前景JavaScript的演變:當前的趨勢和未來前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

神秘的JavaScript:它的作用以及為什麼重要神秘的JavaScript:它的作用以及為什麼重要Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python還是JavaScript更好?Python還是JavaScript更好?Apr 06, 2025 am 12:14 AM

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。

如何安裝JavaScript?如何安裝JavaScript?Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

在Quartz中如何在任務開始前發送通知?在Quartz中如何在任務開始前發送通知?Apr 04, 2025 pm 09:24 PM

如何在Quartz中提前發送任務通知在使用Quartz定時器進行任務調度時,任務的執行時間是由cron表達式設定的。現�...

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境