」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > JavaScript 中的非同步程式設計:回呼、Promise、Async/Await

JavaScript 中的非同步程式設計:回呼、Promise、Async/Await

發佈於2024-07-31
瀏覽:964

Asynchronous Programming in JavaScript: Callbacks vs Promises vs Async/Await

异步编程是 JavaScript 的一个关键方面,它允许开发人员在不阻塞主线程的情况下执行长时间的网络请求、文件操作和其他耗时的任务。这可确保应用程序保持响应灵敏且用户友好。 JavaScript 提供了三种主要方式来处理异步操作:回调、Promises 和 Async/Await。在本文中,我们将深入研究这些方法,通过详细的示例探索它们的语法、用法和差异。

目录

  1. 异步编程简介
  2. 回调
    • 语法和示例
    • 的优点和缺点
  3. 承诺
    • 语法和示例
    • 链接承诺
    • 的优点和缺点
  4. 异步/等待
    • 语法和示例
    • 错误处理
    • 的优点和缺点
  5. 比较和最佳实践
  6. 结论

异步编程简介

在 JavaScript 中,需要时间才能完成的操作(例如从服务器获取数据、读取文件或执行计算)可以异步处理。这意味着在等待操作完成时,JavaScript 引擎可以继续执行其他任务。这对于在 Web 应用程序中创建高效、流畅的用户体验至关重要。

回调

语法和示例

回调是 JavaScript 中最早处理异步操作的方法之一。回调只是一个作为参数传递给另一个函数的函数,该函数将在异步操作完成后执行。

function fetchData(callback) {
    setTimeout(() => {
        callback("Data fetched!");
    }, 1000);
}

function displayData(data) {
    console.log(data);
}

fetchData(displayData);

在上面的例子中,fetchData使用setTimeout模拟异步操作。 1 秒后,它调用 displayData 函数,将获取的数据作为参数传递。

的优点和缺点

优点:

  • 简单明了的小任务。
  • 提供了一种在异步操作完成后执行代码的方法。

缺点:

  • 多个异步操作嵌套时会导致“回调地狱”,导致代码难以阅读和维护。
  • 错误处理很麻烦,因为需要在每个回调中管理错误。

承诺

语法和示例

ES6 (ECMAScript 2015) 中引入了 Promise 来解决与回调相关的问题。 Promise 代表尚未完成但预计将来会完成的操作。它可以处于三种状态之一:待处理、已完成或已拒绝。

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Data fetched!");
        }, 1000);
    });
}

fetchData()
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.error("Error:", error);
    });

在此示例中,fetchData 返回一个 Promise,该 Promise 解析为“Data fetched!” 1秒后。 then 方法用于处理解析后的值,catch 用于处理任何错误。

链接承诺

Promise 可以链接起来按顺序执行一系列异步操作。

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Data fetched!");
        }, 1000);
    });
}

function processData(data) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(`${data} Processed!`);
        }, 1000);
    });
}

fetchData()
    .then(data => {
        console.log(data);
        return processData(data);
    })
    .then(processedData => {
        console.log(processedData);
    })
    .catch(error => {
        console.error("Error:", error);
    });

本例中,在fetchData之后调用processData,并使用then按顺序处理结果。

的优点和缺点

优点:

  • 通过允许异步操作的链接来避免回调地狱。
  • 通过 catch 提供内置错误处理。
  • 提高代码可读性和可维护性。

缺点:

  • 通过多个嵌套的 then 调用仍然会变得复杂。
  • 链中的错误处理可能很重要。

异步/等待

语法和示例

Async/Await 在 ES2017 中引入,提供了一种更可读、更简洁的方式来使用 Promises 编写异步代码。 async 关键字用于定义异步函数,await 关键字用于暂停执行,直到 Promise 得到解析。

async function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Data fetched!");
        }, 1000);
    });
}

async function displayData() {
    const data = await fetchData();
    console.log(data);
}

displayData();

在此示例中,displayData 是一个异步函数,它在记录数据之前等待 fetchData 完成。

错误处理

可以使用 try/catch 块来完成 Async/Await 的错误处理。

async function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("Failed to fetch data!");
        }, 1000);
    });
}

async function displayData() {
    try {
        const data = await fetchData();
        console.log(data);
    } catch (error) {
        console.error("Error:", error);
    }
}

displayData();

这里,如果 fetchData 失败,错误将被 catch 块捕获并记录。

的优点和缺点

优点:

  • 简化异步代码,使其看起来更像同步代码。
  • 增强代码可读性和可维护性。
  • 使用 try/catch 块简化错误处理。

缺点:

  • 需要了解 Promise,因为 Async/Await 是建立在 Promise 之上的。
  • 仍然相对较新,因此某些环境可能不完全支持它。

比较和最佳实践

比较

  • 回调:适合简单的单级异步任务,但在复杂场景下可能会导致回调地狱。
  • Promises:提高可读性和可管理性,允许异步操作的链接。使用 catch 内置错误处理。
  • Async/Await:提供最具可读性和可维护性的异步代码编写方式。简化错误处理并且看起来像同步代码。

最佳实践

  • 对于大多数需要处理异步操作的场景,使用 Async/Await。它提供了最佳的可读性和简单性。
  • 当您需要按顺序执行多个异步操作或使用返回 Promises 的库时,请使用 Promises
  • 避免回调除非使用遗留代码或处理非常简单的异步任务。

结论

JavaScript 中的异步编程对于构建响应迅速且高效的应用程序至关重要。了解回调、Promises 和 Async/Await 之间的差异使开发人员能够为其特定用例选择正确的工具。虽然回调是处理异步操作的最简单形式,但它们可能会导致代码混乱。 Promise 提供了一种更加结构化的方法,但 Async/Await 提供了最优雅和可读的解决方案。通过遵循最佳实践并了解这些工具,开发人员可以编写干净、可维护且高效的异步代码。

版本聲明 本文轉載於:https://dev.to/itsshaikhaj/asynchronous-programming-in-javascript-callbacks-vs-promises-vs-asyncawait-690?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何從 Python 3 的 `map()` 迭代器取得列表?
    如何從 Python 3 的 `map()` 迭代器取得列表?
    在Python 3.x 中檢索映射列表:map() 作為迭代器在Python 3.x 中,map()函數傳回一個迭代器而不是列表。實施此更改是為了提高記憶體效率並優化效能。但是,如果您需要將映射值作為清單檢索以進行進一步處理,則會帶來挑戰。 解決方案:將迭代器轉換為列表要檢索映射值作為列表,使用li...
    程式設計 發佈於2024-12-21
  • 插入資料時如何修復「常規錯誤:2006 MySQL 伺服器已消失」?
    插入資料時如何修復「常規錯誤:2006 MySQL 伺服器已消失」?
    插入記錄時如何解決「一般錯誤:2006 MySQL 伺服器已消失」介紹:將資料插入MySQL 資料庫有時會導致錯誤「一般錯誤:2006 MySQL 伺服器已消失」。當與伺服器的連線遺失時會出現此錯誤,通常是由於 MySQL 配置中的兩個變數之一所致。 解決方案:解決此錯誤的關鍵是調整wait_tim...
    程式設計 發佈於2024-12-21
  • 為什麼我的子選擇器無法設定表格儲存格的樣式?
    為什麼我的子選擇器無法設定表格儲存格的樣式?
    表結構中的子選擇器與後代選擇器在HTML 文件中選擇元素時,開發者經常使用子選擇器(>) 來定位指示子層級和後代選擇器以任何巢狀元素為目標。但是,在某些情況下,子選擇器似乎會意外失敗。 考慮以下範例:table tr td { background-color: red; } table >...
    程式設計 發佈於2024-12-21
  • 想學習 Node.js?對於初學者來說最好的資源是什麼?
    想學習 Node.js?對於初學者來說最好的資源是什麼?
    踏上Node.js 之旅:初學者綜合指南 踏上Node.js 之旅:初學者綜合指南Node.js 已成為世界上一股強大的力量Web 開發,但開始使用這個尖端平台可能會令人畏懼。本文旨在透過提供全面的指南來幫助您踏上 Node.js 之旅來應對這項挑戰。 官方資源與替代選項雖然官方資源Node.js...
    程式設計 發佈於2024-12-21
  • 為什麼 GCC 無法在非命名空間範圍內編譯顯式專業化?
    為什麼 GCC 無法在非命名空間範圍內編譯顯式專業化?
    非命名空間範圍中的顯式專業化儘管在Clang 中編譯成功,但給定的程式碼無法在GCC 中編譯。根據 C 標準 ([temp.expl.spec]),可以在可以定義對應主模板的任何作用域中聲音明​​顯式特化。 此行為似乎是 GCC 中的一個錯誤。根據 CWG 727,[temp.expl.spec] ...
    程式設計 發佈於2024-12-21
  • !和 ?在打字稿中。
    !和 ?在打字稿中。
    有沒有想過那些神秘的符號是什麼!和 ?在 TypeScript 中做些什麼? ?它們可能很小,但威力很大! 以下是使用它們的方式和原因。 ? - 可選修飾符 使用?將屬性或參數標記為可選。它告訴 TypeScript,「嘿,這個欄位可能未定義。」 interface User { ...
    程式設計 發佈於2024-12-21
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-12-21
  • 什麼是多態性?探索 Java 中的型別-物件關係
    什麼是多態性?探索 Java 中的型別-物件關係
    在學習Java的時候,遇到了多態的概念。我傾向於在深入實際使用之前掌握基本原理,因此我在這裡記錄了我的解釋。 我見過的多態性的常見解釋 多態的本義是「多元」。然而,在本文的上下文中,它指的是變數能夠保存不同類型的對象,只要透過類別繼承或介面實現存在關係,而不會導致錯誤。 ...
    程式設計 發佈於2024-12-21
  • 如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    在 PHP 中組合關聯數組在 PHP 中,將兩個關聯數組組合成一個數組是常見任務。考慮以下請求:問題描述:提供的代碼定義了兩個關聯數組,$array1 和 $array2。目標是建立一個新陣列 $array3,它合併兩個陣列中的所有鍵值對。 此外,提供的陣列具有唯一的 ID,而名稱可能重疊。要求是建...
    程式設計 發佈於2024-12-21
  • 儘管程式碼有效,為什麼 POST 請求無法擷取 PHP 中的輸入?
    儘管程式碼有效,為什麼 POST 請求無法擷取 PHP 中的輸入?
    解決PHP 中的POST 請求故障在提供的程式碼片段中:action=''而非:action="<?php echo $_SERVER['PHP_SELF'];?>";?>"檢查$_POST陣列:表單提交後使用 var_dump 檢查 $_POST 陣列的內...
    程式設計 發佈於2024-12-21
  • 為什麼在 C++ 中可以透過 Const 引用傳遞右值?
    為什麼在 C++ 中可以透過 Const 引用傳遞右值?
    使用常數引用保留右值:A C 難題使用常數引用保留右值:A C 難題void display(const int& a) { cout << a; } int main() { int a = 5; display(a); // Works with an lv...
    程式設計 發佈於2024-12-21
  • 在 Go 中使用 WebSocket 進行即時通信
    在 Go 中使用 WebSocket 進行即時通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSocke...
    程式設計 發佈於2024-12-21
  • 如何增加 Java 堆疊大小並確定最佳大小以避免 StackOverflowError?
    如何增加 Java 堆疊大小並確定最佳大小以避免 StackOverflowError?
    了解Java 堆疊大小在Java 中,遇到StackOverflowError 可能表明運行時調用堆疊大小對於特定任務來說太小。當執行緒的堆疊沒有足夠的記憶體來容納程式執行期間​​進行的巢狀方法呼叫時,就會出現此錯誤。 增加 Java 堆疊大小要增加 Java 堆疊大小,可以使用命令列標誌 -Xss...
    程式設計 發佈於2024-12-21
  • 如何在C++中高效地將整數轉換為十六進位字串?
    如何在C++中高效地將整數轉換為十六進位字串?
    在C 中將整數轉換為十六進位字串儘管很簡單,但在C 中將整數轉換為十六進位字串可能會給開發人員帶來挑戰。與 C 不同,C 缺乏用於此轉換的本機方法。 但是,可以利用 函式庫的強大功能來完成此任務。 std::hex 操縱器在過程中起著至關重要的作用。透過將其插入輸出流中,可以以十六進位格式列印整數...
    程式設計 發佈於2024-12-21
  • 如何有效防止 PHP 網站受到跨站腳本 (XSS) 攻擊?
    如何有效防止 PHP 網站受到跨站腳本 (XSS) 攻擊?
    避免PHP 網站中的XSS 攻擊避免PHP 網站中的XSS 攻擊您已採取一些措施來防止PHP 網站上的XSS 攻擊,例如啟用魔術引號並禁用暫存器全域變數。您也可以使用 htmlentities() 函數來轉義使用者輸入的輸出。然而,這些措施並不總是足夠的。 $escaped_string = esc...
    程式設計 發佈於2024-12-21

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3