1. 回调函数
在 JavaScript 中,异步编程是处理时间消耗任务(如网络请求、文件读取等)的核心技术之一。回调函数是处理异步操作的最基本方式。
什么是回调函数
回调函数是作为参数传递给另一个函数的函数,当那个函数完成其任务后会调用这个回调函数。此模式常用于处理异步操作。以下是一个基本示例:
function loadScript(src, callback) {let script = document.createElement("script");script.src = src;script.onload = () => callback(null, script);script.onerror = () => callback(new Error(`Script load error for ${src}`));document.head.append(script);}// 使用回调函数加载脚本loadScript("path/to/script.js", (error, script) => {if (error) {console.error(error);} else {console.log(`${script.src} has been loaded successfully.`);}});
使用回调函数处理异步操作
回调函数非常有用,但当多个异步操作需要串行执行时,回调函数会导致回调地狱问题。以下是多个异步操作的示例:
loadScript("script1.js", (error, script1) => {if (error) {console.error(error);} else {loadScript("script2.js", (error, script2) => {if (error) {console.error(error);} else {loadScript("script3.js", (error, script3) => {if (error) {console.error(error);} else {console.log("All scripts loaded successfully");}});}});}});
2. Promise
Promise 的基本概念
Promise 是异步编程的一种解决方案,它比传统的回调函数和事件更优雅。Promise 可以使异步代码看起来像同步代码,避免了回调地狱。
创建与使用 Promise
Promise 构造函数接受一个回调函数,该回调函数有两个参数:resolve 和 reject。调用 resolve 表示成功,调用 reject 表示失败。例如:
let promise = new Promise((resolve, reject) => {// 异步操作代码setTimeout(() => {resolve("Success!");}, 1000);});// 使用 .then 和 .catch 处理 Promisepromise.then((message) => {console.log(message); // 'Success!'}).catch((error) => {console.error(error);});
Promise 链与错误处理
Promise 支持链式调用,通过 .then() 可以将多个异步操作串联起来。每个 .then() 都返回一个新的 Promise,因此可以继续调用 .then() 或 .catch() 进行错误处理。例如:
loadScript("script1.js").then((script1) => {console.log(`${script1.src} loaded`);return loadScript("script2.js");}).then((script2) => {console.log(`${script2.src} loaded`);return loadScript("script3.js");}).then((script3) => {console.log("All scripts loaded successfully");}).catch((error) => {console.error(`Error: ${error.message}`);});
3. async/await
async/await 的基本概念
async 和 await 是基于 Promise 的语法糖,使得异步代码看起来像同步代码,从而简化异步操作。async 函数总是返回一个 Promise,await 只能在 async 函数中使用。
使用 async/await 简化异步代码
下面是一个使用 async/await 简化后的异步操作示例:
async function loadAllScripts() {try {let script1 = await loadScript("script1.js");console.log(`${script1.src} loaded`);let script2 = await loadScript("script2.js");console.log(`${script2.src} loaded`);let script3 = await loadScript("script3.js");console.log("All scripts loaded successfully");} catch (error) {console.error(`Error: ${error.message}`);}}loadAllScripts();
错误处理与同步风格
在 async/await 中,可以使用 try...catch 来处理错误,这种方式类似于同步代码中的错误处理:
async function loadScriptWithErrorHandling(src) {try {let script = await loadScript(src);console.log(`${script.src} loaded successfully`);return script;} catch (error) {console.error(`Error loading script: ${error.message}`);}}loadScriptWithErrorHandling("script1.js");
通过 async/await,我们可以编写出更加清晰、易读的异步代码,大大提高了代码的可维护性。
接下来,我们将进入更加实战和高级的部分,了解如何操作 DOM 和处理浏览器事件。
