掌握异步 JavaScript:回调、Promises 和 Async/Await

理解 JavaScript 异步编程

JavaScript 中的异步编程对于处理耗时任务(例如从 API 获取数据、读取文件或与数据库交互)至关重要。它确保 JavaScript 即使在执行耗时操作时也能保持非阻塞和响应。

同步与异步编程

  • 同步:在同步编程中,任务按顺序一个接一个地执行。例如:
  • console.log("Task 1");
       console.log("Task 2");
       console.log("Task 3");

    输出:

    Task 1  
       Task 2  
       Task 3
  • 异步:在异步编程中,任务可以并发运行。程序在等待异步任务完成时继续执行其他任务。示例:
  • console.log("Task 1");
       setTimeout(() => console.log("Task 2"), 1000);
       console.log("Task 3");

    输出:

    Task 1  
       Task 3  
       Task 2

    JavaScript 异步中的关键概念

  • 回调:作为参数传递给其他函数的函数,在操作完成后执行。例如:
  • function fetchData(callback) {
         setTimeout(() => {
           console.log("Data fetched");
           callback();
         }, 1000);
       }
    
       fetchData(() => console.log("Callback executed"));
  • Promises:表示异步操作最终完成或失败。Promise 的状态:待定 已实现 已拒绝
  • **例子**:

    const promise = new Promise((resolve, reject) => {
         let success = true;
         if (success) resolve("Operation successful");
         else reject("Operation failed");
       });
    
       promise
         .then(result => console.log(result))
         .catch(error => console.error(error));
  • Async/Await:用于处理 Promise 的语法糖,使异步代码看起来像同步的。示例:
  • async function fetchData() {
         try {
           const response = await fetch("https://api.example.com/data");
           const data = await response.json();
           console.log(data);
         } catch (error) {
           console.error("Error fetching data:", error);
         }
       }
    
       fetchData();

    常见异步操作

  • setTimeout 和 setInterval:延迟后或者间隔重复执行操作。
  • setTimeout(() => console.log("Executed after 1 second"), 1000);
       setInterval(() => console.log("Repeats every second"), 1000);
  • 使用 API 获取数据:使用 fetch 异步检索数据。
  • fetch("https://api.example.com/data")
         .then(response => response.json())
         .then(data => console.log(data))
         .catch(error => console.error("Error:", error));
  • 事件监听器:异步处理用户交互。
  • document.querySelector("button").addEventListener("click", () => {
         console.log("Button clicked");
       });

    异步代码中的错误处理

  • 使用承诺:使用 .catch() 来处理错误。
  • fetch("https://api.example.com/data")
         .then(response => response.json())
         .catch(error => console.error("Error:", error));
  • 使用 Async/Await:使用 try-catch 块进行错误处理。
  • async function fetchData() {
         try {
           const data = await fetch("https://api.example.com/data");
           console.log(data);
         } catch (error) {
           console.error("Error fetching data:", error);
         }
       }

    异步 JavaScript 的最佳实践

  • 避免回调地狱:使用 promise 或 async/await 来避免深度嵌套的回调。回调地狱示例:
  • asyncTask1(() => {
         asyncTask2(() => {
           asyncTask3(() => {
             console.log("Tasks complete");
           });
         });
       });

    承诺解决方案:

    asyncTask1()
         .then(() => asyncTask2())
         .then(() => asyncTask3())
         .then(() => console.log("Tasks complete"))
         .catch(error => console.error(error));
  • 优雅地处理错误:始终将 .catch() 与承诺一起使用或将 try-catch 与 async/await 一起使用。
  • 优化性能:使用 Promise.all() 来并发执行独立任务。
  • const promise1 = fetch("https://api.example.com/data1");
       const promise2 = fetch("https://api.example.com/data2");
    
       Promise.all([promise1, promise2])
         .then(responses => Promise.all(responses.map(res => res.json())))
         .then(data => console.log(data))
         .catch(error => console.error(error));

    结论

    了解异步编程对于构建高效且响应迅速的 JavaScript 应用程序至关重要。通过掌握回调、承诺和异步/等待,您可以编写更干净、更易于维护的异步代码,有效地处理错误,并优化实际应用程序的性能。掌握 JavaScript 异步是现代 Web 开发的关键。