1. 回调函数

在 JavaScript 中,异步编程是处理时间消耗任务(如网络请求、文件读取等)的核心技术之一。回调函数是处理异步操作的最基本方式。

什么是回调函数

回调函数是作为参数传递给另一个函数的函数,当那个函数完成其任务后会调用这个回调函数。此模式常用于处理异步操作。以下是一个基本示例:

  1. function loadScript(src, callback) {
  2. let script = document.createElement("script");
  3. script.src = src;
  4. script.onload = () => callback(null, script);
  5. script.onerror = () => callback(new Error(`Script load error for ${src}`));
  6. document.head.append(script);
  7. }
  8. // 使用回调函数加载脚本
  9. loadScript("path/to/script.js", (error, script) => {
  10. if (error) {
  11. console.error(error);
  12. } else {
  13. console.log(`${script.src} has been loaded successfully.`);
  14. }
  15. });

使用回调函数处理异步操作

回调函数非常有用,但当多个异步操作需要串行执行时,回调函数会导致回调地狱问题。以下是多个异步操作的示例:

  1. loadScript("script1.js", (error, script1) => {
  2. if (error) {
  3. console.error(error);
  4. } else {
  5. loadScript("script2.js", (error, script2) => {
  6. if (error) {
  7. console.error(error);
  8. } else {
  9. loadScript("script3.js", (error, script3) => {
  10. if (error) {
  11. console.error(error);
  12. } else {
  13. console.log("All scripts loaded successfully");
  14. }
  15. });
  16. }
  17. });
  18. }
  19. });

2. Promise

Promise 的基本概念

Promise 是异步编程的一种解决方案,它比传统的回调函数和事件更优雅。Promise 可以使异步代码看起来像同步代码,避免了回调地狱。

创建与使用 Promise

Promise 构造函数接受一个回调函数,该回调函数有两个参数:resolvereject。调用 resolve 表示成功,调用 reject 表示失败。例如:

  1. let promise = new Promise((resolve, reject) => {
  2. // 异步操作代码
  3. setTimeout(() => {
  4. resolve("Success!");
  5. }, 1000);
  6. });
  7. // 使用 .then 和 .catch 处理 Promise
  8. promise
  9. .then((message) => {
  10. console.log(message); // 'Success!'
  11. })
  12. .catch((error) => {
  13. console.error(error);
  14. });

Promise 链与错误处理

Promise 支持链式调用,通过 .then() 可以将多个异步操作串联起来。每个 .then() 都返回一个新的 Promise,因此可以继续调用 .then().catch() 进行错误处理。例如:

  1. loadScript("script1.js")
  2. .then((script1) => {
  3. console.log(`${script1.src} loaded`);
  4. return loadScript("script2.js");
  5. })
  6. .then((script2) => {
  7. console.log(`${script2.src} loaded`);
  8. return loadScript("script3.js");
  9. })
  10. .then((script3) => {
  11. console.log("All scripts loaded successfully");
  12. })
  13. .catch((error) => {
  14. console.error(`Error: ${error.message}`);
  15. });

3. async/await

async/await 的基本概念

asyncawait 是基于 Promise 的语法糖,使得异步代码看起来像同步代码,从而简化异步操作。async 函数总是返回一个 Promise,await 只能在 async 函数中使用。

使用 async/await 简化异步代码

下面是一个使用 async/await 简化后的异步操作示例:

  1. async function loadAllScripts() {
  2. try {
  3. let script1 = await loadScript("script1.js");
  4. console.log(`${script1.src} loaded`);
  5. let script2 = await loadScript("script2.js");
  6. console.log(`${script2.src} loaded`);
  7. let script3 = await loadScript("script3.js");
  8. console.log("All scripts loaded successfully");
  9. } catch (error) {
  10. console.error(`Error: ${error.message}`);
  11. }
  12. }
  13. loadAllScripts();

错误处理与同步风格

async/await 中,可以使用 try...catch 来处理错误,这种方式类似于同步代码中的错误处理:

  1. async function loadScriptWithErrorHandling(src) {
  2. try {
  3. let script = await loadScript(src);
  4. console.log(`${script.src} loaded successfully`);
  5. return script;
  6. } catch (error) {
  7. console.error(`Error loading script: ${error.message}`);
  8. }
  9. }
  10. loadScriptWithErrorHandling("script1.js");

通过 async/await,我们可以编写出更加清晰、易读的异步代码,大大提高了代码的可维护性。

接下来,我们将进入更加实战和高级的部分,了解如何操作 DOM 和处理浏览器事件。