Fetch

Fetch是一种网络通信协议,用于在客户端和服务器之间传输数据

Fetch使用HTTP请求和响应进行通信,与传统的Ajax方式相比更加简单易用,并提供了许多现代化的功能

Fetch可以方便地向服务器发送请求,并将响应返回给客户端

Fetch能够获取文本、JSON、图像和文件等数据,并进行各种处理

Fetch还支持流式传输和取消请求等高级功能,使得处理大型数据集和长时间运行的操作变得更加简单和可靠

Fetch API也是JavaScript中常用的API之一,它提供了一组方法和属性,可以在浏览器端与服务器进行通信

通过Fetch API,可以轻松地使用Fetch协议进行数据传输,并对请求和响应进行操作和处理

Fetch VS XHR

fetch和XMLHttpRequest (XHR)都是前端与服务器进行数据交互的常用方式

它们各有优缺点,具体选择哪种方式还需要根据具体情况进行考虑

但平时开发中使用较多的还是fetch,因其使用方便、API 简洁、语法清晰,同时也支持大多数常用的功能,可以有效地简化前端开发流程

API 设计和使用方式

  • fetch API设计更加现代化、简洁和易用,使用起来更加直观和方便

    • 但无法设置超时时间,需要自行实现
    • 取消请求较为麻烦,需要基于某个构造函数完成
    • 没有progress事件,无法监听文件上传进度,除非使用切片上传
  • XHR API设计比较繁琐,需要进行多个参数的配置和回调函数的处理,且其API已停止维护

支持的请求方法

  • fetch API默认只支持GET和POST请求方法

  • XHR则支持所有标准的HTTP请求方法

请求头部

  • fetch设置请求头部的方式更加清晰直接,可以通过Headers对象进行设置

  • XHR的方式相对较为繁琐

请求体

发送POST请求时

  • fetch API要求将请求体数据作为参数传递给fetch方法中的options对象

  • XHR可以直接在send()方法中设置请求体数据

支持的数据类型

解析响应数据时

  • fetch API提供了多种方法,包括json()blob()arrayBuffer()

  • XHR只支持文本和二进制数据两种数据类型

跨域请求

进行跨域请求时

  • fetch API提供了一种简单而强大的解决方案:使用 CORS(跨域资源共享)头部实现跨域请求
  • XHR则使用一个叫做XMLHttpRequest Level 2的规范,在代码编写上相对较为繁琐

使用Fetch

发送Get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const btn = document.getElementById('send')

const sendFetch = ()=> {
// Get请求 参数1:url 参数2:配置项(请求方式默认Get) 参数3:返回值,是个promise
fetch('http://localhost:3000/api/txt')
// promise会返回fetch的response响应体对象
.then(res=> {
// text()将响应体解析为纯文本字符串并返回
// json()将响应体解析为JSON格式并返回一个JavaScript对象
// blob()将响应体解析为二进制数据并返回一个blob对象
// arrayBuffer()将响应体解析为二进制数据并返回一个ArrayBuffer对象
// formData()将响应体解析为FormData对象
// 指定返回的方式
return res.text()
}).then(data=> {console.log(data)})
}

btn.addEventListener('click', sendFetch)

发送Post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const btn = document.getElementById('send')

const sendFetch = ()=> {
fetch('http://localhost:3000/api/post', {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'yajue',
age: 24
})
})
.then(res=> {
return res.json()
}).then(data=> {console.log(data)})
}

btn.addEventListener('click', sendFetch)

请求进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const btn = document.getElementById('send')
const progress = document.getElementById('progress')

const sendFetch = () => {
fetch('http://localhost:3000/api/txt').then(async res => {
// 克隆一份流用于获取内容
const response = res.clone()

// 制作进度条的方式:获取当前的进度和总进度
// 返回一个用于制作进度条的流
const reader = res.body.getReader()
// 总长度(字节
const total = res.headers.get('Content-Length')
// 用于记录当前流进度
let loaded = 0
while(true) {
// done如果为true,代表数据请求完成,否则还有数据
// value是返回的unit8Array buffer流
const { done, value } = await reader.read()
// 请求完成则终止循环
if(done) {
break
}
// 增加当前进度
loaded += value.length
progress.innerHTML = `${(loaded/total*100).toFixed(2)}%`
}

// 在克隆的流身上获取返回值
return response.text()
}).then(data => {
console.log(data)
})
}

btn.addEventListener('click', sendFetch)

中断请求和超时处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const btn = document.getElementById('send')
const stop = document.getElementById('stop')

// 取消请求用的构造器
const abort = new AbortController()

const sendFetch = () => {
fetch('http://localhost:3000/api/txt', {
// 配置项加上这一行,AbortController实例身上就会提供一个abort方法
signal: abort.signal
}).then(async res => {
return res.text()
}).then(data => {
console.log(data)
})
}

btn.addEventListener('click', sendFetch)

stop.addEventListener('click', ()=> {
timeout(3000)
})

// 超时处理:封装一个函数,超过时间后中断请求即可
const timeout = (timeout)=> {
setTimeout(() => {
// 中断请求:中断后就可以在promise reject中处理了
abort.abort()
}, timeout)
}