跳至内容
张叶安的小站
用户工具
登录
站点工具
搜索
工具
显示页面
过去修订
反向链接
最近更改
媒体管理器
网站地图
登录
>
最近更改
媒体管理器
网站地图
您的足迹:
javascript:第七章异步基础
本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。
====== 第七章 异步编程基础 ====== ===== 本章目标 ===== * 理解同步与异步编程的区别 * 掌握回调函数的使用方法 * 深入理解Promise的概念与用法 * 学会处理异步操作中的错误 ===== 7.1 同步与异步 ===== ==== 7.1.1 同步编程 ==== 在JavaScript中,默认情况下代码是同步执行的,即按照代码的书写顺序一行一行地执行。只有当上一行代码执行完毕后,才会执行下一行代码。 **同步执行的特点:** * 代码按照顺序执行,易于理解和调试 * 如果某行代码执行耗时较长,会阻塞后续代码的执行 * 整个程序的执行流程是确定且可预测的 <code javascript> console.log('第一步'); console.log('第二步'); console.log('第三步'); // 输出顺序:第一步 → 第二步 → 第三步 </code> ==== 7.1.2 异步编程 ==== 异步编程允许程序在等待某些操作完成时继续执行其他代码,而不会阻塞主线程。这对于处理I/O操作(如网络请求、文件读写)尤为重要。 **异步执行的特点:** * 不会阻塞主线程,提高程序的响应性 * 代码执行顺序不总是按照书写顺序 * 需要特殊的机制来处理异步操作的结果 <code javascript> console.log('第一步'); setTimeout(function() { console.log('第二步(异步)'); }, 1000); console.log('第三步'); // 输出顺序:第一步 → 第三步 → 第二步(异步) </code> ===== 7.2 回调函数 ===== ==== 7.2.1 什么是回调函数 ==== 回调函数(Callback)是作为参数传递给另一个函数的函数,它将在某个特定事件发生时被调用。这是JavaScript中最基本的异步处理方式。 <code javascript> function fetchData(callback) { setTimeout(function() { const data = { id: 1, name: '张三' }; callback(data); }, 1000); } fetchData(function(data) { console.log('获取到数据:', data); }); </code> ==== 7.2.2 回调地狱 ==== 当需要依次执行多个异步操作时,回调函数会层层嵌套,形成所谓的"回调地狱"(Callback Hell),使代码难以阅读和维护。 <code javascript> // 回调地狱示例 getUserData(function(user) { getOrders(user.id, function(orders) { getOrderDetails(orders[0].id, function(details) { getProductInfo(details.productId, function(product) { console.log('产品信息:', product); }); }); }); }); </code> ==== 7.2.3 解决回调地狱的方法 ==== **1. 函数命名拆分** <code javascript> function handleProductInfo(product) { console.log('产品信息:', product); } function handleOrderDetails(details) { getProductInfo(details.productId, handleProductInfo); } function handleOrders(orders) { getOrderDetails(orders[0].id, handleOrderDetails); } function handleUser(user) { getOrders(user.id, handleOrders); } getUserData(handleUser); </code> **2. 使用Promise(推荐)** 将在7.3节详细介绍Promise的使用。 ===== 7.3 Promise对象 ===== ==== 7.3.1 Promise简介 ==== Promise是ES6引入的异步编程解决方案,它表示一个异步操作的最终完成(或失败)及其结果值。Promise有三种状态: * **Pending(等待中)**:初始状态,既未完成也未拒绝 * **Fulfilled(已完成)**:操作成功完成 * **Rejected(已拒绝)**:操作失败 <code javascript> const promise = new Promise(function(resolve, reject) { // 异步操作 setTimeout(function() { const success = true; if (success) { resolve('操作成功!'); } else { reject('操作失败!'); } }, 1000); }); </code> ==== 7.3.2 Promise的基本用法 ==== **then()方法**:用于处理Promise成功的情况 **catch()方法**:用于处理Promise失败的情况 <code javascript> function fetchUserData(userId) { return new Promise(function(resolve, reject) { setTimeout(function() { if (userId > 0) { resolve({ id: userId, name: '用户' + userId }); } else { reject('无效的用户ID'); } }, 1000); }); } // 使用Promise fetchUserData(1) .then(function(user) { console.log('用户信息:', user); return user.id; }) .then(function(userId) { console.log('用户ID:', userId); }) .catch(function(error) { console.error('错误:', error); }); </code> ==== 7.3.3 Promise链式调用 ==== Promise支持链式调用,每个then()方法都会返回一个新的Promise,这样可以避免回调地狱。 <code javascript> function step1() { return new Promise(function(resolve) { setTimeout(function() { console.log('步骤1完成'); resolve(10); }, 1000); }); } function step2(value) { return new Promise(function(resolve) { setTimeout(function() { console.log('步骤2完成,接收值:', value); resolve(value * 2); }, 1000); }); } function step3(value) { return new Promise(function(resolve) { setTimeout(function() { console.log('步骤3完成,接收值:', value); resolve(value + 5); }, 1000); }); } // 链式调用 step1() .then(step2) .then(step3) .then(function(finalResult) { console.log('最终结果:', finalResult); // 25 }); </code> ==== 7.3.4 Promise.all() ==== Promise.all()方法接收一个Promise数组,当所有Promise都成功完成时,返回一个包含所有结果的数组;如果任一Promise失败,则立即返回失败原因。 <code javascript> const promise1 = fetch('/api/users'); const promise2 = fetch('/api/products'); const promise3 = fetch('/api/orders'); Promise.all([promise1, promise2, promise3]) .then(function(responses) { console.log('所有请求完成:', responses); return Promise.all(responses.map(function(r) { return r.json(); })); }) .then(function(data) { console.log('解析后的数据:', data); }) .catch(function(error) { console.error('某个请求失败:', error); }); </code> ==== 7.3.5 Promise.race() ==== Promise.race()方法接收一个Promise数组,返回最先完成(无论成功或失败)的那个Promise的结果。 <code javascript> const fastRequest = new Promise(function(resolve) { setTimeout(function() { resolve('快速请求'); }, 100); }); const slowRequest = new Promise(function(resolve) { setTimeout(function() { resolve('慢速请求'); }, 1000); }); Promise.race([fastRequest, slowRequest]) .then(function(winner) { console.log('获胜者:', winner); // "快速请求" }); // 实际应用:设置超时 function fetchWithTimeout(url, timeout) { const fetchPromise = fetch(url); const timeoutPromise = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('请求超时')); }, timeout); }); return Promise.race([fetchPromise, timeoutPromise]); } </code> ==== 7.3.6 Promise.allSettled() ==== Promise.allSettled()方法等待所有Promise完成(无论成功或失败),返回每个Promise的状态和结果。 <code javascript> const promises = [ Promise.resolve('成功1'), Promise.reject('失败1'), Promise.resolve('成功2'), Promise.reject('失败2') ]; Promise.allSettled(promises) .then(function(results) { results.forEach(function(result) { if (result.status === 'fulfilled') { console.log('成功:', result.value); } else { console.log('失败:', result.reason); } }); }); </code> ===== 7.4 异步错误处理 ===== ==== 7.4.1 Promise中的错误处理 ==== 在Promise链中,任何一个环节发生的错误都会被catch()捕获。 <code javascript> function riskyOperation() { return new Promise(function(resolve, reject) { // 模拟随机失败 if (Math.random() > 0.5) { resolve('操作成功'); } else { reject(new Error('操作失败')); } }); } riskyOperation() .then(function(result) { console.log(result); // 这里也可能抛出错误 throw new Error('处理结果时出错'); }) .catch(function(error) { console.error('捕获到错误:', error.message); }) .finally(function() { console.log('无论成功失败都会执行'); }); </code> ==== 7.4.2 全局错误处理 ==== 对于未处理的Promise拒绝,可以使用unhandledrejection事件进行全局捕获。 <code javascript> window.addEventListener('unhandledrejection', function(event) { console.error('未处理的Promise拒绝:', event.reason); event.preventDefault(); // 防止控制台输出默认错误信息 }); // 创建一个没有catch的Promise Promise.reject('未处理的错误'); </code> ===== 7.5 实战示例 ===== ==== 7.5.1 封装AJAX请求 ==== <code javascript> function request(url, method, data) { return new Promise(function(resolve, reject) { const xhr = new XMLHttpRequest(); xhr.open(method || 'GET', url); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response); } else { reject(new Error('HTTP ' + xhr.status + ': ' + xhr.statusText)); } }; xhr.onerror = function() { reject(new Error('网络请求失败')); }; xhr.send(data ? JSON.stringify(data) : null); }); } // 使用封装的请求 request('/api/user/1') .then(function(data) { return JSON.parse(data); }) .then(function(user) { console.log(user); }) .catch(function(error) { console.error(error); }); </code> ==== 7.5.2 图片预加载 ==== <code javascript> function preloadImage(src) { return new Promise(function(resolve, reject) { const img = new Image(); img.onload = function() { resolve(img); }; img.onerror = function() { reject(new Error('图片加载失败:' + src)); }; img.src = src; }); } // 预加载多张图片 const imageUrls = [ 'https://example.com/image1.jpg', 'https://example.com/image2.jpg', 'https://example.com/image3.jpg' ]; Promise.all(imageUrls.map(preloadImage)) .then(function(images) { console.log('所有图片加载完成'); images.forEach(function(img) { document.body.appendChild(img); }); }) .catch(function(error) { console.error('图片加载失败:', error); }); </code> ===== 本章习题 ===== ==== 基础练习 ==== **练习1:回调函数转换** 将以下使用回调函数的代码转换为使用Promise: <code javascript> function getData(callback) { setTimeout(function() { callback(null, { data: 'some data' }); }, 1000); } </code> **练习2:Promise链** 编写一个Promise链,依次完成以下操作: - 获取用户ID - 根据ID获取用户详情 - 根据用户详情获取订单列表 **练习3:并行请求** 使用Promise.all()同时请求多个API端点,并处理其中可能失败的情况。 ==== 进阶练习 ==== **练习4:重试机制** 实现一个带重试机制的异步请求函数,当请求失败时自动重试指定次数。 <code javascript> function retryRequest(fn, maxRetries) { // 实现重试逻辑 } </code> **练习5:队列执行** 实现一个异步任务队列,限制同时执行的异步任务数量(例如最多3个并发)。 ==== 思考题 ==== 1. 为什么JavaScript需要异步编程?哪些场景适合使用异步? 2. Promise相比回调函数有哪些优势?它解决了什么问题? 3. Promise.all()和Promise.race()分别在什么场景下使用? 4. 如何处理Promise链中某个步骤的错误,同时让后续步骤继续执行? ===== 参考答案 ===== **练习1答案:** <code javascript> function getData() { return new Promise(function(resolve) { setTimeout(function() { resolve({ data: 'some data' }); }, 1000); }); } getData().then(function(data) { console.log(data); }); </code> **练习4答案:** <code javascript> function retryRequest(fn, maxRetries) { return new Promise(function(resolve, reject) { let attempts = 0; function attempt() { fn().then(resolve).catch(function(error) { attempts++; if (attempts < maxRetries) { console.log('重试第' + attempts + '次...'); attempt(); } else { reject(error); } }); } attempt(); }); } // 使用示例 retryRequest(function() { return fetch('/api/data'); }, 3); </code> ===== 小结 ===== 本章我们学习了JavaScript异步编程的基础知识: * **同步与异步**:理解了两者的区别,异步编程可以提高程序响应性 * **回调函数**:掌握了基本的异步处理方式,但也了解了回调地狱的问题 * **Promise**:学习了Promise的创建、链式调用、以及Promise.all()和Promise.race()的用法 * **错误处理**:掌握了Promise中的错误捕获和全局错误处理 下一章我们将深入探讨JavaScript的事件循环机制,理解异步代码的执行原理。
javascript/第七章异步基础.txt
· 最后更改:
2026/02/03 22:30
由
127.0.0.1
页面工具
显示页面
过去修订
反向链接
回到顶部