关于前端
1 MDN¶
什么是MDN?这是一个web工程师的开发者社区
2 React¶
React是一个构建JS的工具,类似于前端的框架。他能让开发着用积木一样的感觉构建网页
- 能让网页开发变得更加简单
- 最流行的前端开发工具之一
3 Code with AI¶
AI其实是构建前端很好的工具,他比人写的要美观多了。——zzh
4 HTML¶
我们使用MDN进行学习。
https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Core/Structuring_content
5 前端基本运转¶
因此,与传统模型不同,许多网站使用 JavaScript API 从服务器请求数据,并在不重新加载页面的情况下更新页面。因此,当用户搜索新产品时,浏览器仅请求更新页面所需的数据——例如要显示的新书集。
这里主要的 API 是 Fetch API。它允许页面中运行的 JavaScript 向服务器发起 HTTP 请求来获取特定的资源。当服务器提供了这些资源时,JavaScript 可以使用这些数据更新页面(通常是通过使用 DOM 操作 API)。请求的数据通常是 JSON,这是一种很好的传输结构化的格式,但也可以是 HTML 或纯文本。
6 JSON¶
JavaScript 对象表示法(JSON)是用于将结构化数据表示为 JavaScript 对象的标准格式,通常用于在网站上表示和传输数据(例如从服务器向客户端发送一些数据,因此可以将其显示在网页上)。你会经常遇到它,所以在本文中,我们向你提供使用 JavaScript 处理 JSON 的所有工作,包括访问 JSON 对象中的数据项并编写自己的 JSON。
6.1 什么是JSON¶
JSON 是一种按照 JavaScript 对象语法的数据格式,这是道格拉斯·克罗克福特推广的。虽然它是基于 JavaScript 语法,但它独立于 JavaScript,这也是为什么许多程序环境能够读取(解读)和生成 JSON。
JSON 可以作为一个对象或者字符串存在,前者用于解读 JSON 中的数据,后者用于通过网络传输 JSON 数据。这不是一个大事件——JavaScript 提供一个全局的 可访问的 JSON 对象来对这两种数据进行转换。
7 fetch api¶
7.1 前情提要¶
咱们用一个生活中的例子来理解:
生活中的"承诺" (Promise)
想象一下,你去一家很火的奶茶店点单:
- 你点单 (发起
fetch
请求):你告诉店员你要一杯珍珠奶茶。 - 店员给你小票 (返回 Promise 对象):店员不会立刻给你奶茶,因为制作需要时间。他会给你一张小票,上面写着你的单号。这张小票就是一个“承诺”(Promise)——承诺你最终会拿到东西(奶茶或者一个坏消息,比如没珍珠了)。
- 这个 Promise 此刻的状态是 "pending" (进行中),你还不知道结果。
- 等待叫号 (Promise 的状态变化):
- 情况A:奶茶做好了 (Promise resolved/fulfilled - 成功):店员叫到你的号,你凭小票拿到了奶茶。
- 情况B:没珍珠了 (Promise rejected - 失败):店员叫到你的号,告诉你珍珠卖完了,问你要不要换别的。
- 拿到奶茶后你做什么 (第一个
.then
):- 如果奶茶做好了(Promise 成功了),你拿到奶茶。这个“拿到奶茶”的动作,就相当于 Promise 成功后执行的第一个函数。
fetch
成功后,你拿到的不是直接的数据,而是一个Response
对象(响应对象),可以理解为“装着奶茶的杯子,但你还没尝味道”。你需要对这个Response
对象做一些处理,比如把它转换成我们能看懂的 JSON 格式数据。
- 尝味道/处理数据 (第二个
.then
):- 你把奶茶的盖子打开,尝了一口(比如
response.json()
或response.text()
)。这个动作也需要一点点时间,所以它本身也可能返回一个新的 Promise。 - 当数据真正被解析完毕(比如 JSON 数据准备好了),你就可以对这个数据做你想做的事情了(比如打印出来,或者在页面上显示)。
- 你把奶茶的盖子打开,尝了一口(比如
- 处理意外情况 (
.catch
):- 如果在任何一步出错了(比如店员告诉你没珍珠了,或者奶茶打翻了),你就需要处理这个“坏消息”。
.catch()
就是专门用来捕获和处理这些错误的。
- 如果在任何一步出错了(比如店员告诉你没珍珠了,或者奶茶打翻了),你就需要处理这个“坏消息”。
- 无论如何都要做的事 (
.finally
):- 不管你最终是拿到了奶茶,还是被告知没珍珠了,你最终都会离开奶茶店。
.finally()
里的代码就是无论 Promise 成功还是失败,都会执行的代码,通常用来做一些清理工作。
- 不管你最终是拿到了奶茶,还是被告知没珍珠了,你最终都会离开奶茶店。
现在我们看 fetch
和 .then
的语法
fetch
的基本语法是: fetch(url, [options])
url
: 你要请求的网址。options
(可选): 一个配置对象,可以设置请求方法 (GET, POST 等)、请求头 (headers)、请求体 (body) 等。
核心:fetch()
返回一个 Promise 对象。
Promise 对象有几个关键方法:
-
.then(onFulfilled, onRejected)
:- 当 Promise 成功 (fulfilled) 时,会调用
onFulfilled
这个函数,并且把成功的结果作为参数传给它。 - 当 Promise 失败 (rejected) 时,会调用
onRejected
这个函数(可选),并且把失败的原因作为参数传给它。 - 重要:
.then()
本身也会返回一个新的 Promise!这就是为什么我们可以链式调用.then().then()...
- 当 Promise 成功 (fulfilled) 时,会调用
-
.catch(onRejected)
:- 这是一个更常用的捕获错误的方式,相当于
.then(null, onRejected)
的语法糖。它会捕获前面任何一个 Promise 链条中发生的错误。
- 这是一个更常用的捕获错误的方式,相当于
-
.finally(onFinally)
:- 无论 Promise 最终是成功还是失败,
onFinally
这个函数都会被执行。它不接收任何参数。
- 无论 Promise 最终是成功还是失败,
一步步分解 fetch
的典型用法:
解释每一步:
-
fetch('https://api.example.com/data')
:- 向服务器发送一个 GET 请求。
- 它立刻返回一个 Promise 对象 (我们叫它
promise1
)。此时promise1
的状态是 "pending"。
-
.then(response => { ... })
:- 这个
.then
是注册在promise1
上的。 - 如果网络请求成功(服务器返回了响应,哪怕是 404 或 500 错误,也算网络层面成功),
promise1
变为 "fulfilled" 状态,并且它的值是一个Response
对象。 - 箭头函数
response => { ... }
就会被执行,response
就是那个Response
对象。 - 在函数内部:
if (!response.ok)
: 我们检查 HTTP 状态码。如果不是 2xx (成功状态),response.ok
会是false
。我们主动throw new Error(...)
来让这个 Promise 链条进入 "rejected" 状态,这样错误就能被.catch
捕获。return response.json();
: 如果response.ok
是true
,我们调用response.json()
。这个方法会读取响应体并尝试将其解析为 JSON。重要的是,response.json()
也返回一个 Promise (我们叫它promise2
)。因为读取和解析响应体也需要时间。这个promise2
会成为当前.then
返回的 Promise。
- 这个
-
.then(data => { ... })
:- 这个
.then
是注册在promise2
上的(也就是上一个.then
中response.json()
返回的那个 Promise)。 - 当
response.json()
成功解析出 JSON 数据后,promise2
变为 "fulfilled" 状态,并且它的值就是解析后的 JavaScript 对象或数组。 - 箭头函数
data => { ... }
就会被执行,data
就是那个解析好的数据。 - 这里你就可以使用
data
了。
- 这个
-
.catch(error => { ... })
:- 如果在
fetch
本身(比如网络断开)、或者第一个.then
(比如response.ok
为false
时我们throw Error
)、或者第二个.then
(比如response.json()
解析失败,虽然不太常见,但如果响应体不是有效的 JSON,它会 reject),任何一个环节出错了,这个.catch
就会被触发。 error
对象包含了错误信息。
- 如果在
-
.finally(() => { ... })
:- 无论整个过程是成功(一路
.then
下来)还是失败(被.catch
捕获),finally
里的回调函数总会被执行。
- 无论整个过程是成功(一路
总结一下为什么 .then
会让人困惑:
- 异步性: 代码不是从上到下立刻执行完的。
.then
里的函数要等前面的 Promise 完成了才会执行。 - 回调函数:
.then(fn)
里的fn
是一个回调函数,它不是立刻执行的,而是被 Promise 系统在未来某个时刻调用的。 - 链式调用和 Promise 的传递: 每个
.then
都会返回一个新的 Promise。如果.then
的回调函数返回一个普通值,那么新的 Promise 会立刻 resolve 并携带这个值。如果回调函数返回另一个 Promise,那么新的 Promise 的状态会依赖于这个内部返回的 Promise。response.json()
就是返回 Promise 的典型例子。
7.2 基本讲解¶
1. 什么是 Fetch API?¶
Fetch API 是一种现代的、基于 Promise 的 JavaScript 接口,用于发起网络请求(HTTP请求)。它是 XMLHttpRequest
(XHR) 的一个更强大、更灵活的替代品。
2. 核心特点¶
- 基于 Promise: 使得异步代码处理更简洁,避免了回调地狱。
- 更简洁的 API: 相比 XHR,语法更直观。
- Request 和 Response 对象: 提供了强大的 Request 和 Response 对象,可以灵活处理请求和响应的各个方面(如头部、主体、状态码等)。
- 跨平台: 可在浏览器和 Node.js (v18+ 内置,早期版本需
node-fetch
模块) 中使用。
3. 基本用法 (GET 请求)¶
关键点: * fetch()
返回一个 Promise。 * 这个 Promise 会在接收到服务器的**响应头**后立即 resolve
,得到一个 Response
对象。 * Response
对象本身并不包含实际数据,你需要调用像 .json()
、.text()
这样的方法来提取响应体,这些方法也会返回 Promise。 * 重要: fetch()
只有在发生网络错误(如无法连接服务器)时才会 reject
。对于 HTTP 错误状态码(如 404, 500),fetch()
仍然会 resolve
,你需要通过检查 response.ok
(true 表示状态码 200-299) 或 response.status
来判断请求是否真的成功。
4. 发送不同类型的请求 (如 POST)¶
fetch()
的第二个参数 (options 对象)常用属性: * method
: 请求方法 (e.g., 'GET'
, 'POST'
, 'PUT'
, 'DELETE'
). 默认为 'GET'
. * headers
: 一个包含请求头的对象或 Headers
对象实例。 * body
: 请求体。可以是 String
, Blob
, BufferSource
, FormData
, URLSearchParams
, ReadableStream
。对于 JSON 数据,通常使用 JSON.stringify()
。 * mode
: 请求模式 (e.g., 'cors'
, 'no-cors'
, 'same-origin'
). * credentials
: 是否发送 cookies (e.g., 'include'
, 'same-origin'
, 'omit'
). * cache
: 缓存模式 (e.g., 'default'
, 'no-store'
, 'reload'
). * signal
: 一个 AbortSignal
对象,用于中止请求。
5. 处理响应 (Response 对象)¶
Response
对象包含服务器返回的所有信息: * response.ok
: 布尔值,true
表示 HTTP 状态码在 200-299 之间。 * response.status
: HTTP 状态码 (e.g., 200, 404, 500)。 * response.statusText
: HTTP 状态文本 (e.g., "OK", "Not Found")。 * response.headers
: 一个 Headers
对象,可以用来获取响应头信息 (e.g., response.headers.get('Content-Type')
)。 * response.url
: 响应的 URL。 * 解析响应体的方法 (都返回 Promise): * response.json()
: 解析为 JSON 对象。 * response.text()
: 解析为纯文本。 * response.blob()
: 解析为 Blob 对象 (用于处理文件/二进制数据)。 * response.formData()
: 解析为 FormData 对象。 * response.arrayBuffer()
: 解析为 ArrayBuffer (用于处理原始二进制数据)。
6. 错误处理¶
- 网络错误:
fetch()
返回的 Promise 会reject
(e.g., DNS 查询失败,服务器无响应)。这些错误会直接进入.catch()
块。 - HTTP 错误: 如 404 (Not Found) 或 500 (Internal Server Error)。
fetch()
不会reject
这些情况,而是会resolve
一个Response
对象。你需要**手动检查response.ok
或response.status
** 并在必要时throw new Error()
,这样才能在.catch()
中统一处理。
7. Headers 对象¶
可以用来创建和管理 HTTP 头部。
8. Request 对象 (可选)¶
可以先创建一个 Request
对象,然后再传递给 fetch()
。这在需要复用请求配置或在 Service Workers 中拦截请求时很有用。
9. 优点总结¶
- 现代、标准。
- Promise 支持,代码更优雅。
- 功能强大,可定制性高。
- 与 Service Workers 等现代 Web API 良好集成。
10. 注意事项¶
- CORS (跨域资源共享): 默认情况下,Fetch API 受同源策略限制。进行跨域请求时,服务器需要正确配置 CORS 头部。
- Cookies: 默认情况下,
fetch()
**不会**发送或接收跨域 cookies。如果需要,设置credentials: 'include'
。 - 无超时设置: Fetch API 本身没有内置的请求超时机制。需要通过
AbortController
结合setTimeout
来实现。 - 错误处理细节: 再次强调,HTTP 错误状态码 (4xx, 5xx) 不会使
fetch()
Promisereject
。